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

PHP如何处理将自身作为元素引用的数组?,php,arrays,recursion,reference,Php,Arrays,Recursion,Reference,假设我声明一个数组: $data = array( 'foo' => 'bar' ); 现在,我将添加对自身的引用作为新元素: $data['baz'] = &$data; 转储$data的内容将导致: Array ( [foo] => bar [baz] => Array ( [foo] => bar [baz] => Array *RECURSION* ) ) 现在,我可以转储$d

假设我声明一个数组:

$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内部,所有内容都存储在一个名为
$data
由ZVAL表示,
$data
中的每个键和每个值都是ZVAL,等等

因此,在初始赋值之后,from PHP创建了三个ZVAL:

   /-------------------\      /-------------------\   
   | ZVAL #1           |  /==>| ZVAL #2           |   
   |   type: array     |  |   |   type: string    |   
   |   data: [         |  |   |   data: "foo"     |
   |      {            |  |   \-------------------/
   |          key: =======/                         /-------------------\
   |          val: ================================>| ZVAL #3           |
   |      }            |                            |   type: string    |
   |   ]               |                            |   data:  "bar"    |
   \-------------------/                            \-------------------/
注意:数组项的内部表示与上面显示的内容不一致;我不想给答案添上不必要的细节。出于同样的原因,ZVAL的表示也被简化。如果您想了解更多关于PHP内部的信息,请阅读源代码和/或

您可以看到,
“foo”
“bar”
被用作数组键/值对的事实无法通过查看它们的zval来确定:您必须知道它们正被数组引用

在赋值
$data['baz']=&$data
之后,您现在有了一个循环引用:ZVAL#1内的某个地方有一个指向ZVAL#1的指针:

那么PHP如何解析$data['baz']['baz']?它知道
$data
由ZVAL#1表示,并且它看到您正试图使用数组语法索引到它。它查看ZVAL,发现它是一个数组,找到具有键
“baz”
的项,并获取表示它的ZVAL。你知道什么?这又是ZVAL#1。这就结束了
$data['baz']
的解析

在下一步中,它会看到您正试图将
$data['baz']
作为一个数组进行索引。它知道,
$data['baz']
由ZVAL#1表示,因此同样的事情最终会再次发生,以此类推


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

实际上,要理解这一点,您需要了解什么是PHP数组。它们不是列表或类似的东西,它们是散列,简而言之。因此PHP存储了一个引用,它是键。问题是,在“递归”数组中,这样的引用指向它是另一个元素,仅此而已(即,它仍然是引用,仅此而已)。而且-不,如果在每次迭代时重新分配元素,就不会出现内存溢出的情况。这就像一个循环链表。它只对单个循环使用内存,而不是对所有副本使用无限内存。数组没有“列”,列是您在将数组元素可视化呈现为表时选择的解释数组元素的方式。@meagar是这样的。此外,虽然我对这一点有正确的想法,但我会等待有人以更正式和更严格的方式解释:)谢谢你的详细回答。这正是我想要的。还有一个问题:你自己键入ascii码了吗?;)@很高兴能帮上忙,是的,我帮了:-)
   /-------------------\      /-------------------\   
   | 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"     |
\===========================/                       \-------------------/