Re: Add __toArray() method to objects that would be called on cast to array

From: Date: Thu, 16 Mar 2017 14:34:25 +0000
Subject: Re: Add __toArray() method to objects that would be called on cast to array
References: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15  Groups: php.internals 
Request: Send a blank email to internals+get-98568@lists.php.net to get a copy of this message
2017-03-16 11:01 GMT-03:00 Marco Pivetta <ocramius@gmail.com>: > Since some folks keep banging on "it's not a BC break", I propose a > challenge in fixing this particular BC break example (reads: find a > different way to make it work, and no warnings/notices allowed): > > I made a very simplistic example of where __toArray will break > existing > API that currently literally accepts any kind of object: > https://3v4l.org/Tj0GH > > For reference, here's the code copy: > > <?php > > class Foo > { > public $bar; > public $baz; > public $taz; > } > > // please note that this API has a signature of object $object > - any > object allowed. > function unsetProperties($object) { > // we ignore inheritance and private properties for simplicity > return array_diff( > array_map( > function (\ReflectionProperty $p) : string { > return $p->getName(); > }, > (new ReflectionClass($object))->getProperties() > ), > array_keys((array) $object) > ); > } > > var_dump(unsetProperties(new Foo)); > > $foo = new Foo; > > unset($foo->baz); > > var_dump(unsetProperties($foo)); > > There are dozens of simpler examples that break (typically, data-mapper > layers): I picked this particular one because there is no other way to > detect unset properties without causing side-effects. > > If __toArray is implemented on an object, the API defined above > will > either report all properties to be unset, or in general produce unreliable > results. > > The current API specification of the (array) operator is as > following: > > * for every SET property produce an array value, with the key being: > * "\0" . $className . "\0" . $propertyName for private properties > * "\0*\0" . $propertyName for protected properties > * $propertyName for public properties > * $propertyName for dynamically defined properties > > This is a **VERY SPECIFIC** behavior that the operator currently > guarantees. Break that, and you can go on github hunting for > (array) cast > usages. > > The behavior was frozen in the current suite in > https://github.com/php/php- > src/blob/8015daeddb7bb4951c808fa253b97753787fb0ea/tests/classes/ > > <https://github.com/php/php-%0Asrc/blob/8015daeddb7bb4951c808fa253b97753787fb0ea/tests/classes/> > array_conversion_keys.phpt (although, now that I notice, doesn't cover > dynamically defined properties - should add that). > > Marco Pivetta > > http://twitter.com/Ocramius > > http://ocramius.github.com/ > I kinda agree that (array) being aware of toArray() is not a very good idea at this point, but... It's still not a BC break. In order for the output of "(array) $obj" to change, one would need to change the implementation of the subject $obj class. Lawyering this as a BC break will just hurt any possibility of advancing the conversation in any direction. IMMO, if anyone would like to proceed with this toArray() proposal, a better object reflection/destructuring API could be provided first. Thanks, Márcio.

« previous php.internals (#98568) next »