有谁可以告诉我为什么以下代码会有不同的结果?
取消设置对象属性
$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
取消设置数组索引
$a = array();
unset($a[1][2]); //it is working fine
unset($a[3][4][5]); //it is working fine
答案 0 :(得分:20)
PHP中的数组允许从基础隐式创建多维数组。即:
$a[] = "something"; //new array created, indexed at 0
$a[] = "yep"; //adds element to end of array (array_push);
以上var_dump
给出:
array(2) {
[0]=>
string(9) "something"
[1]=>
string(3) "yep"
}
在PHP 5.4.x中,没有给出任何通知。你也可以这样做:
$a[] = "something";
$a[1][2][3] = "yep";
隐式创建所有级别的数组,给出var_dump
:
array(2) {
[0]=>
string(9) "something"
[1]=>
array(1) {
[2]=>
array(1) {
[3]=>
string(3) "yep"
}
}
}
PHP旨在轻松处理这种类型的数组创建。有关如何处理数组的更多信息,请阅读Array Type文档。因此,如果访问数组中的键以进行值赋值,如果它尚不存在,则会隐式创建它。与unset
一起使用时,不会抛出任何错误,因为它可以检查最终数组并看到它不存在。
因为这是object
,所以必须明确创建属性,而不是投射到它的内容。例如:
$s = new StdClass;
$s->a = new stdClass;
$s->a->b = new stdClass;
$s->a->b->c = "test";
将屈服:
object(stdClass)#1 (1) {
["a"]=>
object(stdClass)#2 (1) {
["b"]=>
object(stdClass)#3 (1) {
["c"]=>
string(4) "test"
}
}
}
当我们创建达到该点所需的object
时。但是,如果您尝试使用:
$s = new StdClass;
$s->a->b->c = "test";
您收到错误:
警告:从第x行的file.php中的空值创建默认对象
但是,然后创建对象,给出var_dump
:
object(stdClass)#1 (1) {
["a"]=>
object(stdClass)#2 (1) {
["b"]=>
object(stdClass)#3 (1) {
["c"]=>
string(4) "test"
}
}
}
当你通过值a
并创建一个默认对象,然后b
,然后为对象属性b->c
赋值“测试”。当转到unset
对象中的值时,它不会将所有属性转换为默认对象。例如,
$s = new StdClass;
unset($s->a->b);
不会给您一个错误,因为a
可以是$s
的属性,并且会对对象执行默认类型转换,然后取消设置b
。但是,它不会在列表中继续下去。
unset($s->a->b->c);
假设b
是a
中的已创建对象,但事实并非如此,因此您尝试使用b->c
来访问非对象的属性。一个更明确的例子:
$s = new stdclass;
$s->a->b->c = array();
unset($s->a->b->c->d);
unset
此处不会抛出任何错误,因为它会将c
输入到对象,然后unset
d
。尽管如此,您确实会收到警告:它会一直向c
投射到stdClass
。这表明,最后一个元素/类将通过类型转换为对象来访问属性(如果它不是已经存在的属性),但是在使用{{{}时它不会对所有元素进行类型转换以访问最后一个属性1}}。
总之,区别在于PHP如何处理数组以及它如何处理对象。对象具有更严格的标准,并且不会隐式地类型转换为多个级别,因为它们被访问为unset
,而数组则是。{1}}。对于对象,您可以隐式地将它们创建为所需的级别(像您一样获得警告),但是当取消设置时,不会发生类型转换,并且您正在访问不存在的属性。