I have a multidimensional array, and some of the elements are objects. I want to end up with 2 arrays, one which has had all string values and object properties passed through my esc() function, and one which is the unmodified original.
Given the following code:
$raw = $data;
echo $raw['obj']->description; // Prints '< >Test Desc'
array_walk_recursive($data, function (&$item, $key){
if(is_string($item)) {
$item = esc($item);
} elseif(is_object($item)) {
foreach ($item as $property => $value) {
if(is_string($value)) {
$item->$property = esc($value);
}
}
}
});
echo $data['obj']->description; // Prints '< >Test Desc' - Correct
echo $raw['obj']->description; // Prints '< >Test Desc' - Incorrect
I would expect $raw to be entirely unmodified, and $data to have been processed through esc(). This is the case except for object properties. For some reason the object in $raw is also modified, so that the two echo
lines print different values, why is this?
since PHP 5 objects are always pass-by-reference.
you have to "clone" the objects to really copy them.
see http://php.net/manual/en/language.oop5.references.php for details.
Objects are passed by reference in PHP. This means that if you assign an object $a
to a variable $b
, both $a
and $b
will point to the same object. This explained in more detail in the Objects and references manual page.
You can use the clone
operator to really make a clone of an object:
$b = clone $a;
This only works for objects, though, so you must recursively make a copy of your array where you use clone
for objects.
PHP's under-the-hood pass-object-by-reference is at work here.
In a nutshell, PHP naturally passes objects by reference, and this includes array members. If you want a proof of this, try the following script:
<?php $arr = array(new stdClass()); var_dump($arr[0]); $arr2 = $arr; var_dump($arr[0]); ?>
The output will be object(stdClass)[1]
in both cases.
There are a couple of solutions for you to use. You can, for example, make use of the clone
operator for objects. If you know the structure of the array, this is trivial. If you don't, you'll have an issue, as PHP cannot clone
the array (and so, you'll need to recursively walk it). All the other solutions include duplicating your object data before editing it.