About error "Attempt to modify property of non-object"

php

Solution

StdClass vs Array

Array

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.

StdClass

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`.

Conclusion

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.

Problem

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 ```

Original source