9

谁能告诉我为什么下面的代码会有不同的结果?

取消设置对象属性

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

1 回答 1

20

标准类与数组

大批

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

$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 旨在轻松处理这种类型的数组创建。有关如何处理数组的更多信息,请阅读数组类型文档。因此,如果您访问数组中的键以进行值分配,如果它尚不存在,则会隐式创建它。与 结合使用时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“test”值时,这是您“期望的”。访问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然后. 您确实会收到警告,它会一直投射到好像。这表明,最后一个元素/类将通过类型转换为一个对象以访问该属性(如果它还不是一个),但它不会在使用时将所有元素类型转换为访问最后一个属性。unsetdcstdClassunset

结论

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

于 2013-05-03T18:00:07.030 回答