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
>

Reply via email to