Re: Add __toArray() method to objects that would be called on cast to array
| From: | Marco Pivetta | Date: | Thu, 16 Mar 2017 14:55:36 +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 16 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-98569@lists.php.net to get a copy of this message | ||
On Thu, Mar 16, 2017 at 3:34 PM, Marcio Almada <marcio.web2@gmail.com>
wrote:
> 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.
>
That's pretty much the point: we need to have a way to keep API that works
with object to keep working with object (BC).
A different API for extracting all properties is sufficient, as long as it
stays stable and survives the __toArray change.
Marco Pivetta
http://twitter.com/Ocramius
http://ocramius.github.com/