On 6/7/24 10:35, Rob Landers wrote:
On Fri, Jun 7, 2024, at 18:03, Benoît Condaminet wrote:
Hello,
Following the RFC process, I'm sending this to propose a PHP change.
More precisely a new zend language token.
This is somehow linked to the recently accepted RFC called "new
MyClass()->method() without parentheses", the goal is to introduce a
shorthand for the "new" keyword.
*Motivations :*
The new keyword sometime has a bad DX, for example when chaining
Class instantiation like this :
$foobar = new Foo( new Bar(), new Etc());
We can quickly have very long class object construction in some case.
In lot of Framework, to improve DX, static function construct are
often used to avoid the new keyword, some create additional object
builders, etc.
As a first try, I start updated code to completely make the new
keyword optional, like in Dart language for example, but it require
very big change, with lot of impact (collision with function).
So here is *my proposal : *
Add a "new" shorthand, using the tilde character : "~"
I made a POC, and it works well, declaring a new language
token T_SHORT_NEW that simply reuse ZEND_AST_NEW under the hood.
Here are some example of what it may look like for userland, through
some tests I wrote :
--TEST-- New keyword shorthand
--FILE-- <?php class A { public function b() { echo "I'm B"; } }
~A()->b(); ?>
--EXPECT-- I'm B
Other with nested :
--TEST-- New keyword shorthand encapsulation
--FILE-- <?php class Foo { public function __construct( public string
$name ) {} } class Bar { public function __construct( public Foo $foo
) {} } $bar = ~Bar(~Foo("I'm foo in bar")); echo $bar->foo->name; ?>
--EXPECT-- I'm foo in bar
As a last word, just wanted to add it will work on nested Attribute
too, so for example this nested Attribute used in Doctrine :
#[AttributeOverrides([
new AttributeOverride(
name: "id",
column: new Column(name: "guest_id", type: "integer", length:
140)
),
new AttributeOverride(
name: "name",
column: new Column(name: "guest_name", nullable: false,
unique: true, length: 240)
)]
)]
Will also work like this :
#[AttributeOverrides([
~AttributeOverride(
name: "id",
column: new Column(name: "guest_id", type: "integer", length:
140)
),
~AttributeOverride(
name: "name",
column: new Column(name: "guest_name", nullable: false,
unique: true, length: 240)
)]
)]
About implementation, it should'n have any impact on SAPI or
extension, the new keyword will still exist, it's just a new shorthand.
I think you get the point, is it something that some of you would be
interested in? I would be happy to make a proper RFC proposal.
Just registered a wiki account : benconda
Thank you,
--
Cordialement,
Benoit Condaminet
Instead of ~ (which reminds me of the pendulum of symbols to written
to symbols and back again every 10ish years; “or” vs “||”), why not
make a shorthand way to write a function that calls a constructor
(kinda sorta like C# extension methods)? Something kinda like:
class MyClass implements Invocable {
public function __construct($i) {}
}
MyClass($i);
Where the Invocable interface defines a function of the same class
name in the namespace that is an alias for a new objects and forwards
args to the constructor. This could be quite handy for value objects.
I’m not necessarily a fan of magic or symbols, but just tossing it out
there to spark ideas.
— Rob
--
I'm not a fan of using ~ for this shorthand, due to the same issues that
have been brought up elsewhere (i.e. it already has meaning). But the
idea of a new interface auto-defining a function of the same name is
attractive. It's something I've done manually to mirror code in PHP from
other implementations existing in Scala leveraging case classes.
https://docs.scala-lang.org/tour/case-classes.html for anyone unfamiliar
with the construct:
```
case class Book(isbn: String)
val frankenstein = Book("978-0486282114")
```
Doing something like this in PHP is a bit more ... verbose today:
```
class Book
{
public function __construct(public string $isbn) {}
}
function Book(string $isbn): Book
{
return new Book($isbn);
}
$frankenstein = Book("978-0486282114")
```
That's a lot of boilerplate for the shorthand to not require a `new`
keyword. Which is to say, I both agree in principle with the RFC and
think this would add value (particularly if I could extend the default
behavior of this kind of interface to support immutability, comparison,
etc similar to Scala case classes). I'm just not a fan of the current ~
proposal.
~Eric