php 关于错误“尝试修改非对象的属性”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16364840/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 10:59:46  来源:igfitidea点击:

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

php

提问by Jasper

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

回答by Jon

StdClass vs Array

标准类与数组

Array

大批

Arrays in PHP allow for the implicit creation of multidimensional arrays from the base. ie:

PHP 中的数组允许从基础隐式创建多维数组。IE:

$a[] = "something"; //new array created, indexed at 0
$a[] = "yep"; //adds element to end of array (array_push);

The var_dumpof the above gives:

var_dump上面给出:

array(2) {
  [0]=>
  string(9) "something"
  [1]=>
  string(3) "yep"
}

In PHP 5.4.x no notices are given either. You could also do:

在 PHP 5.4.x 中也没有给出通知。你也可以这样做:

$a[] = "something";
$a[1][2][3] = "yep";

And alllevels of the array are implicitly created giving the var_dumpof:

并且数组的所有级别都是隐式创建var_dump的:

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

PHP 旨在轻松处理这种类型的数组创建。有关如何处理数组的更多信息,请阅读数组类型文档。因此,如果您访问数组中的键进行值分配,如果它不存在,则会隐式创建它。当与 结合使用时unset,不会抛出错误,因为它可以检查最终数组并查看它的键不存在。

StdClass

标准类

Because this is an object, properties must be explicitly created past what was cast in to it. For example:

因为这是一个object,所以必须显式创建属性,而不是被强制转换的内容。例如:

$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:

当我们创建object达到该点所需的's 时。但是,如果您尝试使用:

$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

警告:从第 x 行的 file.php 中的空值创建默认对象

However, the object is then created giving the var_dumpof:

但是,然后创建对象,给出以下var_dump内容:

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 aand creates a default object, then band then assigns the object property b->cwith the value of "test". When going to unsetthe values in an object, it won't go through casting all the properties to default objects for you. For example,

这是您在遍历值a并创建默认对象时“期望”的结果b,然后将对象属性分配b->c为“test”值。在访问unset对象中的值时,它不会为您将所有属性转换为默认对象。例如,

$s = new StdClass;
unset($s->a->b);

Won't give you an error because acan 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.

不会给你一个错误,因为a可以是 的属性$s,并且会将默认类型转换为对象,然后取消设置b。但是,它不会在列表中更进一步。

unset($s->a->b->c);

Will go with the assumption that bis 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:

将假设b是 内创建的对象a,但事实并非如此,因此您尝试使用 访问非对象的属性b->c。一个更明确的例子:

$s = new stdclass;
$s->a->b->c = array();
unset($s->a->b->c->d);

the unsethere won't throw any errors, because it will type-cast cto to an object and then unsetthe d. You do get the warning that it casts all the way up to cas stdClassthough. 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.

unset这里不会抛出任何错误,因为这将类型转换c到一个对象,然后unsetd。你得到警告说,这蒙上一路攀升到c作为stdClass虽然。这表明,最后一个元素/类将通过类型转换为一个对象来访问该属性,如果它不是一个,但它不会在使用时将所有元素类型转换为访问最后一个属性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.

总之,区别在于 PHP 处理数组的方式和处理对象的方式。对象具有更严格的标准,并且不会在访问时隐式转换为多个级别unset,而数组则是。对于对象,您可以隐式地将它们创建到所需的级别(在执行时收到警告),但是当未设置时,不会发生类型转换,并且您正在访问不存在的属性。