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
About error "Attempt to modify property of non-object"
提问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_dump
of 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_dump
of:
并且数组的所有级别都是隐式创建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_dump
of:
但是,然后创建对象,给出以下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 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,
这是您在遍历值a
并创建默认对象时“期望”的结果b
,然后将对象属性分配b->c
为“test”值。在访问unset
对象中的值时,它不会为您将所有属性转换为默认对象。例如,
$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.
不会给你一个错误,因为a
可以是 的属性$s
,并且会将默认类型转换为对象,然后取消设置b
。但是,它不会在列表中更进一步。
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:
将假设b
是 内创建的对象a
,但事实并非如此,因此您尝试使用 访问非对象的属性b->c
。一个更明确的例子:
$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
.
在unset
这里不会抛出任何错误,因为这将类型转换c
到一个对象,然后unset
将d
。你得到警告说,这蒙上一路攀升到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
,而数组则是。对于对象,您可以隐式地将它们创建到所需的级别(在执行时收到警告),但是当未设置时,不会发生类型转换,并且您正在访问不存在的属性。