Re: Improving PHP's Object Egonomics: A broad analysis
| From: | Larry Garfield | Date: | Mon, 23 Mar 2020 20:20:42 +0000 |
| Subject: | Re: Improving PHP's Object Egonomics: A broad analysis | ||
| References: | 1 2 3 4 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-109256@lists.php.net to get a copy of this message | ||
On Mon, Mar 23, 2020, at 2:47 PM, Michał Brzuchalski wrote:
> Hi Larry,
> > The value here is combining constructor promotion with named parameters.
> > Constructor promotion itself is useful for the class implementer, but
> > doesn't help the caller. Named parameters helps the caller, but doesn't
> > really help the class implementer. The combination of both of them
> > together gives us something similar to the object-initializer syntax as a
> > net result, but with many other benefits because it's not a one-off syntax.
> >
> > So with the two of them together, you get:
> >
> > class Point {
> > public function __construct({public int $x, public int $y});
> > }
> >
> > Which then allows any of these construction mechanisms:
> >
> > $p1 = new Point(5, 7);
> > $p2 = new Point({x: 5, y: 7});
> > $p3 = new Point({y: 7, x: 5});
> >
> > All of which result in an object you can use the same way:
> >
> > print $p1->x . ', '. $p1->y;
> >
> >
> I agree it looks a little bit awkward and differs from object-initializers
> known from other languages,
> but let's say it would work somehow for this example. Now make it not 2 but
> 10-15 properties
> with real types sometimes quite long so after 3-5 of them you should break
> the line,
> then add some default values.
> Like a real entity which with typed properties doesn't need setters and
> getters.
>
> The example grows but even when breaking a line after each
> parameter/property still could be somehow readable.
>
> Now as we deal with Entity add some annotations or let's go hype, try
> with
> new Attributes v2
> proposed by Benjamin Eberlei
>
> https://wiki.php.net/rfc/attributes_v2#userland_use-casemigrating_doctrine_annotations_from_docblocks_to_attributes
> 3 for $id and for the rest at least one attribute per property.
>
> class Product {
> public function __construct({
> <<ORM\Id>>
> <<ORM\Column>>
> <<ORM\GeneratedValue>>
> public int $id,
>
> <<ORM\Column(["unique" => true])>>
> public string $name,
>
> <<ORM\Column>>
> public string $description
> });
> }
>
> Let's stop on 3 I think it's enough to see it's:
> 1. unusual to see annotations in method signature declaration
> 2. not readable anymore.
>
> Now if you say it shouldn't be like that and all the properties should be
> declared as normal properties,
> then the constructor is not needed to simplify the declaration but still
> requires a lot of boilerplate on
> the caller side undoubtedly.
>
> Do you still think object-initializer is pointless and useless and can be
> replaced with
> named arguments and constructor arguments promotion?
>
> Cheers,
> Michał
Yes, I responded to the annotations point in my earlier reply. I hadn't considered those, so
we'll likely need to consider alternate syntaxes if we want both annotations and constructor
promotion (which I do). However, note that even the (admittedly fugly) Product example you have
above, each property name is listed only once, not 4 times, making it still an improvement on the
status quo as far as redundancy.
However, I still hold that constructor promotion and named parameters, taken together, are strictly
superior to a one-off syntax for objects that only supports public properties, as they offer more
capabilities and have less potential to be confused with future additions.
Eg, object-initalizer syntax vs named parameters on a constructor; which to use when? Why? Why do
both exist? They really shouldn't. Named params would be better than object-initalizers all
on their own, regardless of whether constructor promotion is included, precisely because they offer
more capability for the same syntactic addition.
--Larry Garfield