PHP如何处理作为元素引用自身的数组?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (1)
  • 关注 (0)
  • 查看 (37)

比方说我声明一个数组:

$data = array( 'foo' => 'bar' );

现在我将添加一个对自身的引用作为一个新元素:

$data['baz'] = &$data;

倾倒内容$data将导致:

Array
(
[foo] => bar
[baz] => Array
    (
        [foo] => bar
        [baz] => Array
         *RECURSION*
    )

)

现在,我可以转储内容$data['baz']['baz']['baz']['baz']['baz']['baz']['baz']['baz']['baz']并且结果与上述内容完全相同,因为数组有一个指向自身的指针作为元素。

我想知道的是,如果php将数组作为一个单一的数据集处理,并且指针与我在使用时指向的指针完全相同,$data或者它完成了一些完全不同的操作。

此外,PHP可能会在尝试返回内容时耗尽内存$data{['baz']*n}

提问于
用户回答回答于

在PHP内部,所有内容都存储在称为ZVAL的变体容器中。由ZVAL表示,每个键和每个值都是ZVAL等。$data$data

所以在初始分配后,PHP创建了三个ZVAL:

   /-------------------\      /-------------------\   
   | ZVAL #1           |  /==>| ZVAL #2           |   
   |   type: array     |  |   |   type: string    |   
   |   data: [         |  |   |   data: "foo"     |
   |      {            |  |   \-------------------/
   |          key: =======/                         /-------------------\
   |          val: ================================>| ZVAL #3           |
   |      }            |                            |   type: string    |
   |   ]               |                            |   data:  "bar"    |
   \-------------------/                            \-------------------/

你可以看到这样的事实"foo""bar"被用作数组键/值对是不可能通过看他们的变量容器,以确定:你要知道,他们正在由数组引用。

分配之后$data['baz'] = &$data,会发生什么情况?你现在有一个循环引用:位于ZVAL#1内的某个位置有一个指向ZVAL#1的指针:

   /-------------------\      /-------------------\   
   | ZVAL #1           |  /==>| ZVAL #2           |   
/=>|   type: array     |  |   |   type: string    |   
|  |   data: [         |  |   |   data: "foo"     |
|  |      {            |  |   \-------------------/
|  |          key: =======/                         /-------------------\
|  |          val: ================================>| ZVAL #3           |
|  |      },           |                            |   type: string    |
|  |      {            |                            |   data: "bar"     |
|  |          key: =========================\       \-------------------/
|  |          val: =========\               |       
|  |      }            |    |               |       /-------------------\
|  |   ]               |    |               \======>| ZVAL #4           |
|  \-------------------/    |                       |   type: string    |
|                           |                       |   data: "baz"     |
\===========================/                       \-------------------/

那么PHP如何解决$data['baz']['baz']?它知道这$data是由ZVAL#1表示的,它看到你正试图用数组语法对它进行索引。它看着ZVAL,看到它是一个数组,找到具有该键的项目"baz"并获取表示该项目的ZVAL。你知道什么?这再次是ZVAL#1。这就结束了决议$data['baz']

在下一步中,它看到你正在尝试将$data['baz']数组索引。它知道这$data['baz']是由ZVAL#1表示的,所以同样的事情最终会再次发生,等等。

你将注意到上述过程不涉及存储任何中间结果(第一步和第二步完全独立),这意味着在尝试解析数组访问时,PHP虚拟机不会遇到任何资源限制。

扫码关注云+社区