Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:93690 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 95354 invoked from network); 1 Jun 2016 19:03:33 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 1 Jun 2016 19:03:33 -0000 Authentication-Results: pb1.pair.com smtp.mail=alex@netvps.ca; spf=pass; sender-id=pass Authentication-Results: pb1.pair.com header.from=alex@netvps.ca; sender-id=pass Received-SPF: pass (pb1.pair.com: domain netvps.ca designates 209.85.220.177 as permitted sender) X-PHP-List-Original-Sender: alex@netvps.ca X-Host-Fingerprint: 209.85.220.177 mail-qk0-f177.google.com Received: from [209.85.220.177] ([209.85.220.177:34511] helo=mail-qk0-f177.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 39/75-63812-4813F475 for ; Wed, 01 Jun 2016 15:03:33 -0400 Received: by mail-qk0-f177.google.com with SMTP id y126so22163677qke.1 for ; Wed, 01 Jun 2016 12:03:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=netvps-ca.20150623.gappssmtp.com; s=20150623; h=subject:to:references:from:message-id:date:user-agent:mime-version :in-reply-to; bh=Qzg2iSZ+BRUv5JOSwtb+dg6dh4X8py0pL+Ss3rUpfOE=; b=k1MOCtVXebBhUXCM2w4RQO4XUxnMB56Q7uAAA5vIMCu/EoE379v8ZP2oKOeYEojRRd z42UxWBNy3z+oawqO6qjYOjfyx7yfsd+bv6RE4+MK3mu8aOkioMi/behY5zDz29cYoy3 gWDZ4BHRoJuutr9QWmndaFy28tm1BTPNsHXFCZt3FsmbdcmMf9Q51u11YkURiHWu/4YX gA3dN7na6G/uZkK+MTMmKa9j5Ew6MSej0HglY1wuQFx6KJLXWBDv5ljzrwIZUq4wv1UT eDYVFSuJYWJ4/IkzN6MH+RaaO87VYeVVJ4lsFnRq8CHs7dvDmAbwIAam8JhHeU9i2Bak MZ0A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:subject:to:references:from:message-id:date :user-agent:mime-version:in-reply-to; bh=Qzg2iSZ+BRUv5JOSwtb+dg6dh4X8py0pL+Ss3rUpfOE=; b=Ux9Mx1CYHEk0ifDAzq8NYEiDqI60WUe+/StA1x9bp7QUbBWN+DAJpF5lJlonjtZe/q 2FWSnS9D8OFQZPUWbRq5vDGpPJv+0bAbQckAgQ+OU9k3C/HUHUwr+TAa5h/SKKPnv0JC eB6TfRsJV/npaZg91ZKy4SSq9awPNpdzBPL31mksYetqDkFLS3AR8HeJxuFnfheudCXN WHUJByg6Tq0sHThNqU/9c6Ubk4w5xV8ueV661OpREzTqxI5wGil9SX1A4AfHdRdV2us6 UO/8HdnMCy/p9/wntufirOkHgYYhTsLA7WsBvJUh/Ms1jpOM0hCY/JH8h4BRGNNTPXhu 4Z7Q== X-Gm-Message-State: ALyK8tL4wWTuX0kYzx3k07u1Xw2rKCtyrYjQZY6Y+OSxSLNzF0BrH8/nMvyjsYHh/EhP8Q== X-Received: by 10.200.50.59 with SMTP id x56mr5427605qta.63.1464807808990; Wed, 01 Jun 2016 12:03:28 -0700 (PDT) Received: from [192.168.1.10] (modemcable088.204-161-184.mc.videotron.ca. [184.161.204.88]) by smtp.googlemail.com with ESMTPSA id 18sm9379515qkd.31.2016.06.01.12.03.27 for (version=TLSv1/SSLv3 cipher=OTHER); Wed, 01 Jun 2016 12:03:27 -0700 (PDT) To: internals@lists.php.net References: Message-ID: Date: Wed, 1 Jun 2016 15:02:55 -0400 User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:45.0) Gecko/20100101 Thunderbird/45.1.1 MIME-Version: 1.0 In-Reply-To: Content-Type: multipart/alternative; boundary="------------40DF786FC39E34F860E48637" Subject: Re: [PHP-DEV] Set object properties inline From: alex@netvps.ca (Alex Duchesne) --------------40DF786FC39E34F860E48637 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit On 2016-05-31 22:15, 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 > > 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 = ..., > }, > } > ); Is there anything wrong with casting an array to an object? The syntax is almost identical to what you want to achieve. I can think of three ways to achieve, with the current PHP stable, what you seem to desire (forgive me if I misunderstood). Your code becomes: $this->fooMethod( $arg1, $arg2, (object)[ 'prop1' => ..., 'prop2' => ..., 'prop3' => (object)[ 'prop1' => ..., 'prop2' => ..., }, } ); Pretty concise and close to your proposal, right? Another option is anonymous classes $this->fooMethod( $arg1, $arg2, new class { var $prop1 => ..., var $prop2' => ..., var $prop3' => new class { var $prop1' => ..., var $prop2' => ..., }, } ); Or if you need a specific class name for validation or anything: $this->fooMethod( $arg1, $arg2, new class extends FooClass { public $prop1 => ..., $prop2' => ..., $prop3' => new class extends FooBar { public $prop1' => ..., $prop2' => ...; }, } ); Last option is a generic class with a __construct taking an array and creating a populated instance, which can be used as a base/trait to extend dumb classes that only require a name. But you've covered that already. Cheers, > 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 --------------40DF786FC39E34F860E48637--