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