Re: Add __toArray() method to objects that would be called on cast to array
| From: | Marco Pivetta | Date: | Thu, 16 Mar 2017 14:01:55 +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 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-98567@lists.php.net to get a copy of this message | ||
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/
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/