function wrap($arr){ test($arr); }
/// ...
wrap($array);
您的wrap()
函数为$arr
. 当你test()
在 s 体内调用函数时wrap()
,它会引用$arr
内存块,而不是$array
s 内存块,因为$arr
它是一个副本,$array
PHP 内存管理系统将它们分开存储。
有一个通用的参考点功能:
function is_equal_refs(&$a, &$b){
$buffer = $a; // saving current value in temporary variable
$a = md5(time()); // assigning new value to memory block, pointed by reference
$result = ($a === $b); // if they're still equal, then they're point to the same place.
$a = $buffer; // restoring value
return $result; // returning result
}
所以,让我们做一些测试:
<?php
header('Content-Type: text/plain');
function is_equal_refs(&$a, &$b){
$buffer = $a;
$a = md5(time());
$result = ($a === $b);
$a = $buffer;
return $result;
}
function wrap($arr){ test($arr); }
function test(&$arr){
foreach($arr as &$v){
if(is_equal_refs($arr, $v)){
print_r('ref');
echo PHP_EOL;
break;
}
if(is_array($v))return test($v);
print_r($v);
echo PHP_EOL;
}
}
$array = array(1, 2, 3);
$array[] = &$array;
wrap($array);
?>
显示:
1 // < $arr
2
3
1 // < $array
2
3
ref // < $array doubled -> reference found
这种行为的原因是$arr[3]
包含对$array
s内存块的引用,而不是对自身内存块的引用。
让我们删除$array[] = &$array;
一行,并修改wrap()
函数以检查:
function wrap($arr){
$arr[] = &$arr;
test($arr);
}
结果将是:
1 // < $arr
2
3
ref // < $arr doubled -> reference found
因为$arr
不是指向$array
,而是指向本身在$arr[3]
。因此,在您的代码中,您想要发现不同的引用。
结论:您想要实现的是打破 PHP 内存管理规则。
UPDv1:
需要寻求解决方法,以恢复函数范围内$array
的引用。wrap()
1)“坏”/“全局”实践:
<?php
header('Content-Type: text/plain');
function is_equal_refs(&$a, &$b){
$buffer = $a;
$a = md5(time());
$result = ($a === $b);
$a = $buffer;
return $result;
}
function wrap($array){
global $check; // <- THIS
test(empty($check) ? $array : $check); // <- THIS
}
function test(&$arr){
foreach($arr as &$v){
if(is_equal_refs($v, $arr)){
print_r('ref');
echo PHP_EOL;
break;
}
if(is_array($v)){
test($v);
} else {
print $v . ' ';
echo PHP_EOL;
}
}
}
$array = array(1, 2, 3);
$array[] = &$array;
$check = &$array; // <- and THIS
wrap($array);
?>
这表明:
1
2
3
ref
2)“将所有内容包装在数组或对象中”的做法:(首选且可靠)
<?php
header('Content-Type: text/plain');
define('REF_MARKER', 'x-my-tr!cky-ref'); // trick key definition
function is_equal_refs(&$a, &$b){
$buffer = $a;
$a = md5(time());
$result = ($a === $b);
$a = $buffer;
return $result;
}
function wrap(array $arr){
// restore reference, if trick.
// it might be moved to the top part of test() function (might affect performance).
if(isset($arr[REF_MARKER]))$arr = &$arr[REF_MARKER];
test($arr);
}
// $array - subject to test;
// $refs - internal ref list of all `subjects`;
function test(&$array, $refs = array()){
$refs[] = &$array;
foreach($array as &$value){
foreach($refs as &$ref){
if(is_equal_refs($ref, $value))return print 'ref ';
}
if(is_array($value)){
$refs[] = &$value;
test($value, $refs);
} else {
print $value . ' ';
}
}
}
$array = array(1, 2, 3);
$array[] = &$array;
wrap(array(REF_MARKER => &$array)); // trick
print PHP_EOL;
$ring = array(1, 2, 3, array(4, 5, 6));
$ring[3][] = &$ring;
wrap(array(REF_MARKER => &$ring)); // trick
print PHP_EOL;
$test = array('a', 'b', 'c');
$ring = array(1, 2, 3);
$ring[] = &$test;
$test[] = &$ring;
wrap(array(REF_MARKER => &$ring)); // trick
print PHP_EOL;
wrap(range(1, 5)); // normal
print PHP_EOL;
$test = array(1, 2, 3, array(1, 2, 3), 4, array(5, 2, 3), array(6, array(1, 2, 3), 7), array(1, 2, 3));
wrap($test); // normal
print PHP_EOL;
$test[] = &$test;
$test[3][] = &$test;
$test[5][] = &$test[3];
wrap(array(REF_MARKER => &$test)); // trick
?>
显示:
1 2 3 ref
1 2 3 4 5 6 ref
1 2 3 a b c ref
1 2 3 4 5
1 2 3 1 2 3 4 5 2 3 6 1 2 3 7 1 2 3
1 2 3 1 2 3 ref 4 5 2 3 ref 6 1 2 3 7 1 2 3 ref