Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:93679 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 66084 invoked from network); 1 Jun 2016 15:38:31 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 1 Jun 2016 15:38:31 -0000 Authentication-Results: pb1.pair.com smtp.mail=matthewfonda@gmail.com; spf=pass; sender-id=pass Authentication-Results: pb1.pair.com header.from=matthewfonda@gmail.com; sender-id=pass Received-SPF: pass (pb1.pair.com: domain gmail.com designates 209.85.213.44 as permitted sender) X-PHP-List-Original-Sender: matthewfonda@gmail.com X-Host-Fingerprint: 209.85.213.44 mail-vk0-f44.google.com Received: from [209.85.213.44] ([209.85.213.44:35738] helo=mail-vk0-f44.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 4C/20-63812-6710F475 for ; Wed, 01 Jun 2016 11:38:31 -0400 Received: by mail-vk0-f44.google.com with SMTP id d127so32168185vkh.2 for ; Wed, 01 Jun 2016 08:38:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=ADhkvQ8pUk4s3a25YqVsbpgfR2Bsg4sIMPgMcNIRgXs=; b=OVywoERI3QwvTxDBrD36m8CiwQYRwqxJbnw9+q1915thGn2rKoZgV9dXresYqjdHp+ R8G8XHboZY56U7XUMGB650Vro0g67LvOaPTJAglH7VMK8TwGHmSw/N2AP7zmb3aHe82P OC4Nt9kVAi6xDJEZmyrpbXM0gxuyWBo1sWHEuml5zT3n2+iI028wS5sLpQVJ7GFVRUbg c7pu7zvIWlXbqF6dmNYW+fjGLLvFNJ6C4ttFIKB39KgdqvGMhyq9QcKMyahnxqik5f8g I9+DyFvACmnqUpWgQ3NrdpWsDs4Wi8pwj5GB3Zn7Fk/Dj6CI8LdOY9HgXZGa3Y+8G+LO wFpw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=ADhkvQ8pUk4s3a25YqVsbpgfR2Bsg4sIMPgMcNIRgXs=; b=A+qvFb125uE10hmn1+Kt5cuaXgonai60EXj8sAk+T2ffOOF6Wran18NomOH4Hk1PY6 38iUOoWOSRUtwgi3gJaGOqoggxPgYOpgJL8H6zEbVSalGEKDRKuzvOucPdiLHhZ/M22R r+E1RYAsxcB97ADIUrhlEjOVC9pRCzkStEDUyPcGJAmcM/A1Bnbm/CDdLTmS+hRqH4k5 7jv2V4mjYxa8RpUMishwKdIoOwHsqTYwgH8q1HkwhmozmRRU41OuD28+jMVT4lTcvbEe vOjPRaCslfkg7Fvs2Yr9HvM1RIF87KZHFqCUcmDNhCKZVHe23Y5bkqoASSr/GHcpPPlE NYnQ== X-Gm-Message-State: ALyK8tKx3TpvpNvPSZqEMyacogoGsxyCeYqd2lRrYUJQW8gazejBMwXmGOs0Y6iUE1KzxsX3B6tX4D58DdIhhQ== X-Received: by 10.31.109.197 with SMTP id i188mr2141712vkc.157.1464795507872; Wed, 01 Jun 2016 08:38:27 -0700 (PDT) MIME-Version: 1.0 Received: by 10.31.183.13 with HTTP; Wed, 1 Jun 2016 08:37:58 -0700 (PDT) In-Reply-To: References: Date: Wed, 1 Jun 2016 08:37:58 -0700 Message-ID: To: Jesse Schalken Cc: PHP internals Content-Type: multipart/alternative; boundary=94eb2c095ec8ea5ab30534394767 Subject: Re: [PHP-DEV] Set object properties inline From: matthewfonda@gmail.com (Matt Fonda) --94eb2c095ec8ea5ab30534394767 Content-Type: text/plain; charset=UTF-8 On Tue, May 31, 2016 at 7:15 PM, Jesse Schalken 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 = ..., > }, > } > ); > > > 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 > Hi Jesse, It's fairly straightforward to implement a function that does this in userland, for example something like the following: function f($fqcn, $args) { $instance = new $fqcn; foreach ($args as $key => $value) { $instance->$key = $value; } return $instance; } ... $this->fooMethod( $arg1, $arg2, f('FooParams', [ 'prop1' => ..., 'prop2' => ..., 'prop3' => f('Obj1', [ 'prop1' => ..., 'prop2' => ..., ], ]) ); You may also use the approach Peter suggested. As such, I don't think introducing a new syntax for it is necessary. Best, --Matt --94eb2c095ec8ea5ab30534394767--