假设我声明了一个数组:
$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 内部,所有内容都存储在 variant 中称为 ZVAL 的容器. $data
由一个 ZVAL 表示,$data
中的每个键和每个值都是一个 ZVAL,等等。
所以在初始分配之后,从 PHP 中创建了三个 ZVAL:
/-------------------\ /-------------------\
| ZVAL #1 | /==>| ZVAL #2 |
| type: array | | | type: string |
| data: [ | | | data: "foo" |
| { | | \-------------------/
| key: =======/ /-------------------\
| val: ================================>| ZVAL #3 |
| } | | type: string |
| ] | | data: "bar" |
\-------------------/ \-------------------/
注意:数组项的内部表示与上面显示的不对应;我不想用不必要的细节来增加答案的负担。出于同样的原因,ZVAL 的表示也被简化显示。如果您想了解更多关于 PHP 内部结构的信息,请阅读源代码和/或 this .
您可以看到 "foo"
和 "bar"
被用作数组键/值对的事实无法通过查看它们来确定ZVAL:您必须知道它们被数组引用。
在赋值 $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 虚拟机没有资源限制。数组访问。
关于php - PHP 如何处理将自身作为元素引用的数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19518534/