有没有办法在纯 PHP 中检测循环数组?
我正在尝试在 PHP 中实现我自己的序列化/var_dump 样式函数。如果存在圆形阵列的可能性(确实存在),这似乎是不可能的。
在最近的 PHP 版本中,var_dump 似乎可以检测循环数组:
php > $a = array();
php > $a[] = &$a;
php > var_dump($a);
array(1) {
[0]=>
&array(1) {
[0]=>
*RECURSION*
}
}
How will I Implement my own serialization type of method in PHP that can detector like?我不能只跟踪我访问过的数组,因为 PHP 中数组的严格比较对于包含相同元素的不同数组返回 true,并且无论如何比较循环数组会导致致命错误。
php > $b = array(1,2);
php > $c = array(1,2);
php > var_dump($b === $c);
bool(true)
php > $a = array();
php > $a[] = &$a;
php > var_dump($a === $a);
PHP Fatal error: Nesting level too deep - recursive dependency? in php shell code on line 1
我一直在寻找一种方法来查找数组的唯一 id(指针),但我找不到。 spl_object_hash 仅适用于对象,不适用于数组。如果我将多个不同数组转换为对象,它们都会获得相同的 spl_object_hash 值(为什么?)。
编辑:
在每个数组上调用 print_r、var_dump 或序列化,然后使用某种机制来检测这些方法检测到的递归的存在是算法复杂性的噩梦,并且基本上会使任何使用速度太慢而无法在大型嵌套数组上实用。
接受的答案:
我接受了下面的答案,这是第一个建议暂时更改数组以查看它是否确实与另一个数组相同的答案。这回答了“如何比较两个数组的同一性?”从中递归检测是微不足道的。
I'm trying to implement my own serialization / var_dump style function in PHP. It seems impossible if there is the possibility of circular arrays (which there is).
In recent PHP versions, var_dump seems to detect circular arrays:
php > $a = array();
php > $a[] = &$a;
php > var_dump($a);
array(1) {
[0]=>
&array(1) {
[0]=>
*RECURSION*
}
}
How would I implement my own serialization type of method in PHP that can detect similarly? I can't just keep track of which arrays I've visited, because strict comparison of arrays in PHP returns true for different arrays that contain the same elements and comparing circular arrays causes a Fatal Error, anyways.
php > $b = array(1,2);
php > $c = array(1,2);
php > var_dump($b === $c);
bool(true)
php > $a = array();
php > $a[] = &$a;
php > var_dump($a === $a);
PHP Fatal error: Nesting level too deep - recursive dependency? in php shell code on line 1
I've looked for a way to find a unique id (pointer) for an array, but I can't find one. spl_object_hash only works on objects, not arrays. If I cast multiple different arrays to objects they all get the same spl_object_hash value (why?).
EDIT:
Calling print_r, var_dump, or serialize on each array and then using some mechanism to detect the presence of recursion as detected by those methods is an algorithmic complexity nightmare and will basically render any use too slow to be practical on large nested arrays.
ACCEPTED ANSWER:
I accepted the answer below that was the first to suggest temporarily altering the an array to see if it is indeed the same as another array. That answers the "how do I compare two arrays for identity?" from which recursion detection is trivial.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
下面的 isRecursiveArray(array) 方法检测循环/递归数组。它通过临时将包含已知对象引用的元素添加到数组末尾来跟踪已访问的数组。
如果您需要帮助编写序列化方法,请更新您的主题问题并在问题中提供示例序列化格式。
The isRecursiveArray(array) method below detects circular/recursive arrays. It keeps track of which arrays have been visited by temporarily adding an element containing a known object reference to the end of the array.
If you want help writing the serialization method, please update your topic question and provide a sample serialization format in your question.
它并不优雅,但解决了您的问题(至少如果您没有人使用 *RECURSION* 作为值)。
It's not elegant, but solves your problem (at least if you dont have someone using *RECURSION* as a value).
有趣的方法(我知道它很愚蠢:)),但您可以修改它并跟踪递归元素的“路径”。这只是一个想法:)根据序列化字符串的属性,递归开始时将与原始数组的字符串相同。正如您所看到的 - 我尝试了许多不同的变体,可能有些东西能够“欺骗”它,但它“检测”所有列出的递归。我没有尝试使用对象的递归数组。
regexp 适用于递归元素位于数组“末尾”的情况。是的,这个递归与整个数组有关。可以对子元素进行递归,但对我来说考虑它们已经太晚了。应该以某种方式检查数组的每个元素的子元素中的递归情况。同样的方式,如上面,通过 print_r 函数的输出,或者在序列化字符串中查找递归的特定记录(
R:4;}
类似这样)。跟踪应该从该元素开始,通过我的脚本比较下面的所有内容。所有这些仅适用于您想检测递归从哪里开始的情况,而不仅仅是您是否有递归。ps:但正如我认为,最好的事情应该是从 php 本身创建的序列化字符串编写自己的反序列化函数。
Funny method (I know it is stupid :)), but you can modify it and track the "path" to the recursive element. This is just an idea :) Based on the property of the serialized string, when recursion starts in will be the same as the string for the original array. As you can see - I tried it on many different variations and might be something is able to 'fool' it, but it 'detects' all listed recursions. And I did not try recursive arrays with objects.
regexp is for the situation when element with recursion is at the 'end' of the array. and, yes, this recursion is related to the whole array. It is possible to make recursion of the subelements, but it is too late for me to think about them. Somehow every element of the array should be checked for the recursion in its subelements. The same way, like above, through the output of the print_r function, or looking for specific record for recursion in serialized string (
R:4;}
something like this). And tracing should start from that element, comparing everything below by my script. All that is only if you want to detect where recursion starts, not just whether you have it or not.ps: but the best thing should be, as I think, to write your own unserialize function from serailized string created by php itself.
我的方法是使用一个临时数组来保存已迭代的所有对象的副本。这里是这样的:
这里有一些快速演示代码来说明它是如何工作的:
这个脚本将生成以下输出:
My approach is to have a temp array that holds a copy of all objects that were already iterated. like this here:
And here is some quick demo code to illustrate how it works:
This script will generate the following output:
这是我的方法。关键是通过引用递归函数 simple_var_dump() 来传递数组,并使用标签(在本例中为“iteating_in_a_higher_level”)来区分在更高嵌套级别中迭代的数组。
输出:
This is my approach. The key is to pass the array by reference to the recursive function simple_var_dump(), and use a tag (in this case "iterating_in_a_higher_level") to distinguish the arrays that are being iterated in a higher nesting level.
Output: