Can anyone tell me why the following code will have different results ?
unset object property
$s = new StdClass;
unset($s->a->b); //it is working fine
unset($s->x->y->z); //it is got an error: Attempt to modify property of non-object
unset array index
$a = array();
unset($a[1][2]); //it is working fine
unset($a[3][4][5]); //it is working fine
Arrays in PHP allow for the implicit creation of multidimensional arrays from the base. ie:
$a[] = "something"; //new array created, indexed at 0
$a[] = "yep"; //adds element to end of array (array_push);
The var_dump
of the above gives:
array(2) {
[0]=>
string(9) "something"
[1]=>
string(3) "yep"
}
In PHP 5.4.x no notices are given either. You could also do:
$a[] = "something";
$a[1][2][3] = "yep";
And all levels of the array are implicitly created giving the var_dump
of:
array(2) {
[0]=>
string(9) "something"
[1]=>
array(1) {
[2]=>
array(1) {
[3]=>
string(3) "yep"
}
}
}
PHP was designed to handle this type of array-creation with ease. For more information on how arrays are handled, please read the Array Type documentation. Because of this, if you access a key within an array for value assignment, if it doesn't already exist, it is implicitly created. When used in conjunction with unset
, no errors are thrown because it can check up to the final array and see that it key doesn't exist.
Because this is an object
, properties must be explicitly created past what was cast in to it. For example:
$s = new StdClass;
$s->a = new stdClass;
$s->a->b = new stdClass;
$s->a->b->c = "test";
Will yield:
object(stdClass)#1 (1) {
["a"]=>
object(stdClass)#2 (1) {
["b"]=>
object(stdClass)#3 (1) {
["c"]=>
string(4) "test"
}
}
}
As we create the object
's required to reach that point. If, however, you try and use:
$s = new StdClass;
$s->a->b->c = "test";
You get the error:
Warning: Creating default object from empty value in file.php on line x
However, the object is then created giving the var_dump
of:
object(stdClass)#1 (1) {
["a"]=>
object(stdClass)#2 (1) {
["b"]=>
object(stdClass)#3 (1) {
["c"]=>
string(4) "test"
}
}
}
Which is what you would 'expect' as it goes through the values a
and creates a default object, then b
and then assigns the object property b->c
with the value of "test". When going to unset
the values in an object, it won't go through casting all the properties to default objects for you. For example,
$s = new StdClass;
unset($s->a->b);
Won't give you an error because a
can be a property of $s
, and will do a default type cast to an object and then unset b
. However, it won't go any further down the list.
unset($s->a->b->c);
Will go with the assumption that b
is a created object within a
, but it is not, so you are trying to access a property of a non-object by using b->c
. A more explicit example:
$s = new stdclass;
$s->a->b->c = array();
unset($s->a->b->c->d);
the unset
here won't throw any errors, because it will type-cast c
to to an object and then unset
the d
. You do get the warning that it casts all the way up to c
as stdClass
though. What this shows, is that the last element/class will by type-cast to an object to access the property if it is not one already, but it won't type-cast all the elements to access the last property when using unset
.
In all, the difference is between how PHP handles arrays and how it handles objects. Objects have a stricter standard and are not implicitly type-cast to multiple levels as they are accessed to be unset
, whereas arrays are. With objects, you can implicitly create them to the levels needed (getting a warning as you do), but when being unset, the type-casting doesn't happen, and you are accessing properties that don't exist.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With