On Thu, Jun 2, 2016 at 12:38 AM, guilhermebla...@gmail.com < guilhermebla...@gmail.com> wrote:
> Hi, > > I very much liked the proposal, specially if we do consider a potential > reusability if anyone ever decide to revisit Attributes RFC. It's out of > scope how I'd see this implemented, so let me focus on the proposal only. > There're some edge cases that need to be discussed and considered here. > Here's one quick example: > > declare("foo", "bar"); > > class Foo { > public $bar; > } > > $f = new Foo() { > foo = "bar" > }; > > Should "foo" be considered as a property identifier or as a constant, > which would then be converted into "bar" and then used as $f->bar = "bar"? > My intention was for "expr->prop = ..." to be equivalent to "expr { prop = ... }", except obviously the result is the object itself and multiple properties can be assigned. So the property name is written directly as an identifier, and wouldn't be looked up as a constant. If expression property names are required I suppose it should mirror the "expr->{expr} = ...;" syntax and become "expr { {expr} ... }". Turns out there is already a "property_name" production in zend_language_parser.y (and also "member_name", but I'm not sure what the difference is), so the grammar would become: expr_without_variable: /* ... */ | expr '{' inline_set_properties '}' ; inline_set_properties: /* empty */ | property_name '=' expr | property_name '=' expr ',' inline_set_properties ; > > Regards, > > > On Wed, Jun 1, 2016 at 5:49 AM, Peter Cowburn <petercowb...@gmail.com> > wrote: > >> On 1 June 2016 at 03:15, Jesse Schalken <m...@jesseschalken.com> wrote: >> >> > Hi internals, >> > >> > I often have code dealing with plain old PHP objects with properties >> and no >> > methods, either as a substitute for keyword arguments, or to represent a >> > JSON or YAML document for a web service, configuration file or >> schemaless >> > database. >> > >> > At the moment, instantiating an object and setting public properties >> > requires a temporary variable for each object in the structure: >> >> >> > $obj1 = new Obj1(); >> > $obj1->prop1 = ...; >> > $obj1->prop2 = ...; >> > >> > $params = new FooParams(); >> > $params->prop1 = ..; >> > $params->prop2 = ...; >> > $params->prop3 = $obj1; >> > >> > $this->fooMethod($arg1, $arg2, $params); >> > >> > >> > For large structures, this gets verbose very quick. There is a good >> example >> > of this here >> > < >> > >> https://github.com/jesseschalken/fail-whale/blob/72870b37c4c21d19f17324a966344ec476b432a7/src/FailWhale/Introspection.php#L22 >> > > >> > involving >> > 18 unnecessarily variables. >> > >> > I can remove the local variables by defining setters for all the >> > properties: >> > >> > $this->fooMethod( >> > >> > $arg1, >> > $arg2, >> > (new FooParams()) >> > >> > ->setProp1(...) >> > >> > ->setProp2(...) >> > >> > ->setProp3((new Obj1()) >> > >> > ->setProp1(...) >> > >> > ->setProp2(...)) >> > >> > ); >> > >> > >> > But now for each property I have to spend an extra 3-5 lines of code >> > defining a setter, which is more code than it saved (unless the class is >> > used heavily enough). >> > >> > I could define __construct() taking every property as a parameter, but >> then >> > each property has to be mentioned another three times (four times with a >> > doc comment), and the type twice: >> > >> > class FooParams { >> > >> > public int $prop1; >> > // ... >> > >> > >> > public function __construct( >> > int $prop1 >> > // ... >> > ) { >> > >> > $this->prop1 = $prop1; >> > // ... >> > >> > } >> > >> > } >> > >> > >> > and where the object is constructed, it isn't immediately visible what >> the >> > meaning of each positional parameter is without some IDE assistance (eg >> > Ctrl+P in PhpStorm), and only specifying some parameters requires >> filling >> > preceding ones with defaults. >> > >> > I could also define the __call() method to automatically expose setters, >> > but then IDEs and static analysis can't understand what's going on (it >> > can't see that those methods exist, what their parameters are and what >> they >> > return). @method doc comments on the class help, but that's another line >> > for every property which I have to manually keep in sync with the real >> > properties. >> > >> > It would be great if there was a simple shorthand syntax for setting >> > properties on an object in-line, without needing to extract a variable: >> > >> > $this->fooMethod( >> > $arg1, >> > $arg2, >> > new FooParams() { >> > prop1 = ..., >> > prop2 = ..., >> > prop3 = new Obj1() { >> > prop1 = ..., >> > prop2 = ..., >> > }, >> > } >> > ); >> > >> >> While it's not as concise as your example, anonymous classes can do this >> already after a fashion. >> >> $this->fooMethod( >> $arg1, >> $arg2, >> new class() extends FooParams { >> // Constructor because prop3's value isn't a constant expression >> function __construct() { >> $this->prop1 = '...'; >> $this->prop2 = '...'; >> $this->prop3 = new class() extends Obj1 { >> public $prop1 = '...'; >> public $prop2 = '...'; >> }; >> } >> } >> ); >> >> >> > >> > >> > This way the structure can be written directly in the code as an >> expression >> > and FooParams and Obj1 remain simple containers for properties. >> > >> > The grammar might look like (I haven't used bison/yacc before): >> > >> > expr_without_variable: >> > /* ... */ >> > | expr '{' inline_set_properties '}' >> > ; >> > >> > inline_set_properties: >> > /* empty */ >> > | identifier '=' expr >> > | identifier '=' expr ',' inline_set_properties >> > ; >> > >> > >> > (Although I think that would conflict with the alternative $var{8} >> syntax >> > for array/string offset.) >> > >> > Has this been explored before? What problems can you foresee (or have >> been >> > foreseen) with such a feature? >> > >> > Thanks >> > >> > > > > -- > Guilherme Blanco > Lead Architect at E-Block >