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

标签 php arrays recursion reference

假设我声明了一个数组:

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

相关文章:

algorithm - 有趣的递归函数

java - 这可以只用递归来完成吗?

php - php mysql中的计算

PHP,检测带水印的图像?

php - 使用特定列中的值替换第一级数组键

ruby - Ruby 中的递归方法性能

php while循环引起的PHP段错误

php - 检查mysql表是否存在记录

arrays - Any 和 AnyObject 之间的 Swift 异常

对象数组的C++方法