添加备注

用户贡献的备注 36 个备注

Dave at SymmetricDesigns dot com
16 年前
另一个使用数组引用时需要注意的事项。似乎即使是数组单元格的未使用引用也会修改引用的 *来源*。对于赋值语句来说这是奇怪的行为(这就是我看到它被写成 =& 运算符的原因吗?——尽管这对普通变量来说不会发生)。
<?php
$array1
= array(1,2);
$x = &$array1[1]; // 未使用的引用
$array2 = $array1; // 引用现在也适用于 $array2!
$array2[1]=22; // (更改 [0] 不会影响 $array1)
print_r($array1);
?>
产生
数组
(
[0] => 1
[1] => 22 // var_dump() 将在此处显示 &
)

我通过在没有引用的情况下重写代码修复了我的错误,但也可以使用 unset() 函数修复它
<?php
$array1
= array(1,2);
$x = &$array1[1];
$array2 = $array1;
unset(
$x); // 数组副本现在不受上述引用的影响
$array2[1]=22;
print_r($array1);
?>
产生
数组
(
[0] => 1
[1] => 2
)
Carlos
19 年前
在下面的示例中,如果你将函数更改为类似于

function test_ref(&$arr) {
$time = time();
$size = sizeof($arr); // <--- 这会导致差异...
for($n=0; $n<$size; $n++) {
$x = 1;
}

echo "<br />The function using a reference took ".(time() - $time)." s";
}
ivan at mailinator dot com
15 年前
一个小技巧(小心引用!)

<?php
$arr
= array('a'=>'first', 'b'=>'second', 'c'=>'third');
foreach (
$arr as &$a); // 不做任何事。也许?
foreach ($arr as $a); // 不做任何事。也许?
print_r($arr);
?>
输出

数组
(
[a] => first
[b] => second
[c] => second
)

在 foreach 之间添加 'unset($a)' 以获得 '正确' 的输出

数组
(
[a] => first
[b] => second
[c] => third
)
alexander at gamerev dot org
10 年前
简单来说,以下是一个引用是什么的示例

<?php
$foo
= 5;
$bar = &$foo;
$bar++;

echo
$foo;
?>

上面的示例将输出值 6,因为 $bar 引用了 $foo 的值,因此,当更改 $bar 的值时,你也会更改 $foo 的值。
gnuffo1 at gmail dot com
13 年前
如果你想了解特定变量的引用计数,那么这里有一个使用 debug_zval_dump() 来执行此操作的函数

<?php
function refcount($var)
{
ob_start();
debug_zval_dump($var);
$dump = ob_get_clean();

$matches = array();
preg_match('/refcount\(([0-9]+)/', $dump, $matches);

$count = $matches[1];

// 添加了 3 个引用,包括调用 debug_zval_dump() 时
return $count - 3;
}
?>

debug_zval_dump() 是一个令人困惑的函数,正如其文档中所解释的那样,因为它除了其他事情之外,还会在被调用时添加引用计数,因为函数中有一个引用。refcount() 会考虑这些额外的引用,并在返回值中减去它们。

当处理通过引用 (=&) 赋值的变量时,情况就更加令人困惑了,无论是在赋值的右侧还是左侧,因此,出于这个原因,上面的函数对于那些类型的变量实际上并不起作用。我会更多地将其用于对象实例。

但是,即使考虑到将变量传递给函数会将引用计数增加 1;这应该意味着调用 refcount() 会增加 1,然后调用 debug_zval_dump() 会再增加 1,refcount() 似乎从某个地方获得了另一个引用;因此在返回行中减去 3 而不是 2。不太确定它来自哪里。

我只在 5.3 上测试过它;由于 debug_zval_dump() 的性质,结果在其他版本上可能完全不同。
mpapec
16 年前
奇怪的是,函数定义和对同一个函数的调用必须在它们之前都有 "&"。

$arr = array();
$ref =& oras($arr['blah'], array());
$ref []= "via ref";
print_r($arr);

/* 结果
数组
(
[blah] => Array
(
[0] => via ref
)

)
*/

// 像 perl 这样的 ||=
function &oras (&$v, $new) {
$v or $v = $new;
return $v;
}
iryoku at terra dot es
20 年前
你应该记住,php4 会自动将分配的变量引用到它们被覆盖之前。因此,变量复制不是在分配时执行的,而是在修改时执行的。假设你有这个

$var1 = 5;
$var2 = $var1; // 在这一点上,这两个变量共享相同的内存位置
$var1 = 3; // 这里 $var1 和 $var2 有自己的内存位置,分别包含值 3 和 5

不要在函数参数中使用引用来加速应用程序,因为这是自动完成的。我认为这应该在手册中,因为它可能会导致混淆。

更多关于这个的信息在这里
http://www.zend.com/zend/art/ref-count.php
midir
15 年前
这是一篇很好的杂志文章(PDF 格式),详细解释了 PHP 引用机制的内部机制:http://derickrethans.nl/files/phparch-php-variables-article.pdf

它应该解释了 PHP 有时表现出的一些奇怪行为,以及为什么你不能创建“对引用的引用”(不像在 C++ 中),以及为什么你永远不应该尝试使用引用来加速大型字符串或数组的传递(它将没有区别,或者会减慢速度)。

它是为 PHP 4 编写的,但仍然适用。唯一的区别在于 PHP 5 如何处理对象:按值传递对象变量只会复制指向对象的内部指针。PHP 5 中的对象只有在你显式使用 clone 关键字时才会被复制。
nathan
20 年前
在说 php4 自动创建引用的帖子中,这似乎 *不* 适用于对象

https://php.net/manual/en/language.references.whatdo.php

"注意:不使用 & 运算符会导致创建对象的副本。如果在类中使用 $this,它将作用于类的当前实例。没有 & 的赋值将复制实例(即对象),而 $this 将作用于副本,这并不总是期望的结果。通常,由于性能和内存消耗问题,您希望使用单个实例。"
hkmaly at bigfoot dot com
19 年前
看起来 PHP 在处理引用方面存在问题,例如无法正确处理循环引用或释放具有多个引用的结构。请参阅 http://bugs.php.net/?id=30053.

我在这方面遇到了很大的问题,我希望 PHP 的某位开发者能够在手册中添加适当的警告和解释,如果他们无法修复它的话。
sneskid at hotmail dot com
12 年前
目前还没有内置方法来检查两个变量是否引用同一块数据,但是您可以进行“引用嗅探”测试。这很少需要,但可以非常有用。下面的函数是对我在一个关于此比较限制的论坛中看到的技术的略微修改版本。

<?php
function is_ref_to(&$a, &$b)
{
$t = $a;
if(
$r=($b===($a=1))){ $r = ($b===($a=0)); }
$a = $t;
return
$r;
}

$varA = 1;
$varB = $varA;
$varC =&$varA;

var_dump( is_ref_to($varA, $varB) ); // bool(false)
var_dump( is_ref_to($varA, $varC) ); // bool(true)
?>

上面的测试使用两步过程来保证 100% 通用。
但如果您确定要测试的变量不会是某个特定值,例如 null,那么可以使用该值来进行一步检查。

<?php
function is_ref_to_1step(&$a, &$b)
{
$t = $a;
$r=($b===($a=null));
$a = $t;
return
$r;
}
?>
php at REMOVEMEkennel17 dot co dot uk
18 年前
我在这篇文章中找到了关于 PHP4 中引用如何工作的非常有用的总结(以及一些常见陷阱):http://www.obdev.at/developers/articles/00002.html

它处理了一些微妙的情况,我建议任何在处理引用时遇到困难的人阅读它。
dnhuff at acm dot org
16 年前
这在之前(下面)已经讨论过,但值得重复说明。

$a = null; ($a =& null; 语法错误) 不等于 unset($a);

$a = null; 将 $a 目标处的值替换为 null 值;

如果您选择使用类似 $NULL = NULL; 的约定

那么,您可以说 $a =& $NULL 来破坏之前对 $a 的任何引用赋值(当然将其设置为 $NULL),如果忘记了然后说 $a = '5',仍然可能导致问题。现在 $NULL 将是 '5'。

道德:在需要的时候使用 unset。
marco at greenlightsolutions dot nl
16 年前
我最近遇到了一些问题,数组复制导致其中一个元素的引用副本而不是克隆。示例代码

<?php
$a
=array(1 => "A");
$b=&$a[1];
$c=$a; // 应该是深度克隆
$c[1]="C";
var_dump($a[1]); // 产生 'C' 而不是 'A'
?>

经过一番搜索,我发现这是一个已知的错误,修复成本太高(请参阅 http://bugs.php.net/bug.php?id=20993)。该页面的行为应该有一些文档

"由于 PHP 内部工作原理的特殊性,如果对数组的单个元素进行引用,然后复制数组(无论是通过赋值还是在函数调用中按值传递),引用将作为数组的一部分被复制。这意味着对这两个数组中任何此类元素的更改将在另一个数组(以及其他引用)中重复,即使数组具有不同的作用域(例如,一个是函数内部的参数,另一个是全局的)!在复制数组时没有引用的元素,以及在复制数组之后分配给其他元素的引用,将按正常方式运行(即独立于另一个数组)。"

然而,这部分内容似乎在某个时候从该页面中删除了,可能是因为它有点晦涩。评论部分似乎是一个合适的地方,可以放置这些内容。
Someone
8 年前
另一个使用数组引用时需要注意的事项。似乎即使是数组单元格的未使用引用也会修改引用的 *来源*。对于赋值语句来说这是奇怪的行为(这就是我看到它被写成 =& 运算符的原因吗?——尽管这对普通变量来说不会发生)。
<?php
$array1
= array(1,2);
$x = &$array1[1]; // 未使用的引用
$array2 = $array1; // 引用现在也适用于 $array2!
$array2[1]=22; // (更改 [0] 不会影响 $array1)
print_r($array1);
?>
产生
数组
(
[0] => 1
[1] => 22 // var_dump() 将在此处显示 &
)

// 上面由 Dave at SymmetricDesign dot com 提出 //
// 以下是我对这个问题的看法。//

这是一个正常的引用问题。

当您获得对某个变量处内存的引用时。
此变量表示“内存本身”。(在上面的例子中,它将是 -> $x = &$array1[1]; // 未使用的引用)

并且您已将原始的 ($array1) 复制到另一个 ($array2)。
复制意味着“将所有内容粘贴到自身上”。包括引用或指针等。因此,当您将 $array1 复制到 $array2 时,$array2 拥有与原始 $array1 相同的引用。这意味着 $x = &$array1[1] = &$array2[1];
我上面又说了一遍,此引用表示“内存本身”。
当您选择向 $array2[1] 插入一些值时,
$x; 引用会受到 $array2[1] 值的影响。因为在分配的内存中,$array2[1] 是 $array1[1] 的副本。这意味着 $array2[1] = $array1[1],也意味着 &$array2[1] = &$array1[1],如上所述。这会导致 $array1[1] 上的内存值重新分配。此时。此主题的问题通过 '$x'(内存本身)解决。这个问题通过取消设置 '$x' 来解决。取消设置此引用会触发 $array2[1] 的内存重新分配。这关闭了复制的 ($array1,它是原始的) 和副本 ($array2) 之间的引用链接。这就是该错误(显然,这不是错误,而是一种误解)触发的来源。关闭引用链接使两个数组对象在内存中分离。这项工作是通过 unset() 函数完成的。此主题是 7 年前发布的,但我只是想澄清一下,这不是一个错误。

如果我的笔记中存在问题,请在上面指出。
jw at jwscripts dot com
19 年前
重新使用之前是引用的变量,而不先取消设置它们,会导致意外行为。

以下代码

<?php

$numbers
= array();

for (
$i = 1; $i < 4; $i++) {
$numbers[] = null;
$num = count($numbers);
$index =& $numbers[$num ? $num - 1 : $num];
$index = $i;
}

foreach (
$numbers as $index) {
print
"$index\n";
}

?>

不会产生
1
2
3

而是
1
2
2

在重新使用变量之前应用 unset($index) 可以解决此问题,并将生成预期的列表
1
2
3
sneskid at hotmail dot com
17 年前
除了 'jw at jwscripts dot com' 关于 unset 的描述外,它还可以用来“分离”变量别名,以便它可以再次作用于唯一的内存块。

以下是一个示例

<?php
define
('NL', "\r\n");

$v1 = 'shared';
$v2 = &$v1;
$v3 = &$v2;
$v4 = &$v3;

echo
'before:'.NL;
echo
'v1=' . $v1 . NL;
echo
'v2=' . $v2 . NL;
echo
'v3=' . $v3 . NL;
echo
'v4=' . $v4 . NL;

// detach messy
$detach = $v1;
unset(
$v1);
$v1 = $detach;

// detach pretty, but slower
eval(detach('$v2'));

$v1 .= '?';
$v2 .= ' no more';
$v3 .= ' sti';
$v4 .= 'll';

echo
NL.'after:'.NL;
echo
'v1=' . $v1 . NL;
echo
'v2=' . $v2 . NL;
echo
'v3=' . $v3 . NL;
echo
'v4=' . $v4 . NL;

function
detach($v) {
$e = '$detach = ' . $v . ';';
$e .= 'unset('.$v.');';
$e .= $v . ' = $detach;';
return
$e;
}
?>

输出 {
before
v1=shared
v2=shared
v3=shared
v4=shared

after
v1=shared?
v2=shared no more
v3=shared still
v4=shared still
}

http://www.obdev.at/developers/articles/00002.html 表示在 PHP 中没有“对象引用”这种东西,但是通过分离,它成为可能。

希望分离,或者类似的东西,将来会成为语言结构。
sneskid at hotmail dot com
17 年前
(v5.1.4)
var_dump 的一个很酷的功能是它可以显示哪些变量是引用(在转储数组时),用 '∫' 表示 int/null,用 '&' 表示 boolean/double/string/array/object。我不明白为什么符号不同。
玩了一会后,我发现了一种更好的分离实现方法(偶然发现的)。var_dump 可以显示发生了什么。

<?php
function &detach($v=null){return $v;}

$A=array('x' => 123, 'y' => 321);
$A['x'] = &$A['x'];
var_dump($A);
/* x became it's own reference...
array(2) {
["x"]=> ∫(123)
["y"]=> int(321)
}*/

$A['y']=&$A['x'];
var_dump($A);
/* now both are references
array(2) {
["x"]=> ∫(123)
["y"]=> ∫(123)
}*/

$z = 'hi';
$A['y']=&detach(&$z);
var_dump($A);
/* x is still a reference, y and z share
array(2) {
["x"]=> ∫(123)
["y"]=> &string(2) "hi"
}*/

$A['x'] = $A['x'];
$A['y']=&detach();
var_dump($A,$z);
/* x returned to normal, y is on its own, z is still "hi"
array(2) {
["x"]=> int(123)
["y"]=> NULL
}*/
?>

要使分离正常工作,您需要在函数声明中使用 '&',并在每次调用它时使用。

当您知道一个变量是引用,并且您想分配一个新值而不会影响引用该内存块的其他变量时,请使用它。您可以使用一个新的常数值、变量或新引用来初始化它,所有这些都可以在一步完成。
Ed
18 年前
回复 Slava Kudinov。您的脚本在按引用传递时花费更长时间的唯一原因是您根本没有修改传递给函数的数组。如果您这样做,执行时间差异会小很多。事实上,按引用传递会更快,即使只是快一点点。
gunter dot sammet at gmail dot com
18 年前
我尝试使用递归函数传递数组引用来创建一个深度为 n 的数组。到目前为止,我还没有太多运气,而且我在网上也找不到任何东西。因此,我最终使用了 eval(),它似乎工作得很好。
<?php
foreach(array_keys($this->quantity_array) AS $key){
if(
$this->quantity_array[$key] > 0){
$combinations = explode('-', $key);
$eval_string = '$eval_array';
foreach(
array_keys($combinations) AS $key2){
$option_key_value = explode('_', $combinations[$key2]);
$eval_string .= '['.$option_key_value[0].']['.$option_key_value[1].']';
}
$eval_string .= ' = '.$this->quantity_array[$key].';';
eval(
$eval_string);
}
}
?>

这将生成一个 n 维数组,它将在 $eval_array 变量中可用。希望它对某人有所帮助!
cesoid at yahoo dot com
18 年前
回复 nathan 的帖子(nathan 回复了 iryoku)。

重要的是要注意从程序员的角度来看 PHP 在做什么,以及它在内部做什么之间的区别。nathan 提到的关于(例如)$something = $this 如何从程序员的角度来看创建一个“副本”的说明,是指从程序员的角度来看创建一个“副本”。也就是说,对程序员来说,在所有实际目的上,$something 都是一个副本,即使在内部还没有复制任何东西。例如,更改成员 $something->somethingVar 中的数据不会更改您当前对象的数据(即不会更改 $this->somethingVar)。

它在内部执行的是一个完全不同的故事。我已经测试了“复制”一个包含 200,000 个元素数组的对象,它几乎不花费任何时间,直到您最终更改其中一个副本中的某些东西,因为在内部它只在需要时才进行复制。原始分配不到一毫秒,但当我更改其中一个副本时,它需要大约四分之一秒。但这只有在我更改 200,000 个元素数组时才会发生,如果我更改对象的单个整数,它又不到一微秒,因此解释器似乎足够聪明,可以复制一些对象的变量,而不是其他变量。

结果是,当您将函数更改为按引用传递时,只有当函数内部的传递变量正在更改其数据时,它才会变得更有效,在这种情况下,按引用传递会导致您的代码更改原始副本的数据。如果您正在传递一个对象并在该对象中调用一个函数,该函数可能会在您不知情的情况下更改该对象,这意味着只要在函数内部使用对象时允许原始副本被影响,您就应该按引用传递对象。

我认为这个故事的真正寓意是:
1) 按引用传递任何应该引用并影响原始副本的东西。
2) 不要按引用传递在函数中肯定不会被更改的东西(对于一个对象,可能无法知道在调用其一个函数时它是否会更改自身)。
3) 如果需要在函数内部更改某些东西而不影响原始副本,请不要按引用传递它,并传递需要更改的最小实际部分,而不是传递例如一个巨大的数组,其中只有一个小的整数将被更改。

或者更短的版本:只有在需要引用原始副本时才按引用传递东西!(并且不要在需要更改它们的一小部分时传递巨大的数组或长字符串!)
shooo dot xz at gmail dot com
10 年前
嗨,我在参考资料上做了一些工作。
以下是我发现的。

问题:通过列对 mysql 结果进行排序

$rewrite_self = gt::recombine(array('lang', 'id'), 'value_column', $sql_result);

public static function recombine($keys, $value, &$arr) {
$ref = array();
$main = &$ref;
foreach($arr as $data) {
foreach($keys as $key) {
if (!is_array($ref[$data[$key]])) $ref[$data[$key]] = array();
$ref = &$ref[$data[$key]];
}
$ref = $data[$value];
$ref = &$main;
}
return $main;
}

array(2) {
["pl"]=>
array(2) {
[2]=>
string(4) "value_column_str"
[3]=>
string(4) "value_column_str2"
}
["en"]=>
array(1) {
[13]=>
string(7) "value_column_str3"
}
}

享受!
Francis dot a at gmx dot net
19 年前
我不知道这是否是一个错误(我使用的是 PHP 5.01),但使用数组引用时应该小心。
我有一个循环非常慢,我花了一些时间才发现大部分时间都浪费在每次循环中的 sizeof() 函数上,我花更多时间才发现这个问题可能与我使用数组引用有关。看看下面的例子

function test_ref(&$arr) {
$time = time();
for($n=0; $n<sizeof($arr); $n++) {
$x = 1;
}
echo "<br />The function using a reference took ".(time() - $time)." s";
}

function test_val($arr) {
$time = time();
for($n=0; $n<sizeof($arr); $n++) {
$x = 1;
}
echo "<br />The funktion using a value took: ".(time() - $time)." s";
}

// 填充数组
for($n=0; $n<2000; $n++) {
$ar[] = "test".$n;
}

test_ref($ar);
test_val($ar);
echo "<br />Done";

当我测试它时,第一个函数在 9 秒后完成,而第二个函数(虽然数组必须被复制)甚至不到一秒钟就完成了。

当数组大小减小时,差异会不成比例地减小
当使用 1000 次循环时,第一个函数运行了 1 秒,当使用 4000 次循环时,它在 30 秒后甚至没有完成。
warnickr at gmail dot com
16 年前
我必须说,遵循所有关于 PHP 引用解释都相当令人困惑,特别是因为我之前用 C 指针做了很多工作。据我所知,就所有实际目的而言,PHP 引用与 C 指针相同。我认为很多困惑都来自下面的例子,人们期望这个例子的 C 指针版本会改变 $bar 引用的内容。

<?php
function foo(&$var)
{
$var =& $GLOBALS["baz"];
}
foo($bar);
?>

情况并非如此。事实上,这个例子的 C 指针版本(如下所示)的行为将与 PHP 引用版本完全相同(它不会修改 bar 引用的内容)。

int baz = 5;
int* bar;
void foo(int* var)
{
var = &baz;
}
foo(bar);

在本例中,就像在 PHP 引用中一样,调用 foo(bar) 不会改变 bar 引用的内容。如果你想改变 bar 引用的内容,那么你需要使用双指针,如下所示

int baz = 5;
int* bar;
void foo(int** var)
{
*var = &baz;
}
foo(&bar);
trucex at gmail dot com
17 年前
回应 Xor 和 Slava

我建议你更多地了解 PHP 处理内存管理的方式。以以下代码为例

<?php

$data
= $_POST['lotsofdata'];
$data2 = $data;
$data3 = $data;
$data4 = $data;
$data5 = $data;

?>

假设我们向此 PHP 文件发送了 10MB 的数据,PHP 将如何处理内存?

PHP 使用一种类似表格的东西,将变量名称映射到内存中该变量所引用的数据。$_POST 超全局变量实际上将是该数据的第一个实例,因此它将是内存中引用该数据的第一个变量。它将消耗 10MB。每个 $data 变量都将简单地指向内存中的相同数据。在您更改该数据之前,PHP 不会复制它。

按值传递变量就像我为每个 $data 变量所做的那样。为相同数据分配一个新名称不会产生重大开销。只有当你修改传递给函数的数据时,它才需要为该数据分配内存。按引用传递变量在将数据传递给函数时将做本质上相同的事情,只是修改它将修改内存中已存在的数据,而不是将其复制到内存中的新位置。

如果您出于学习目的而选择忽略这两种方法之间的差异在基准测试中的明显无用性,则需要在将数据传递给函数时修改该数据,以获得更准确的结果。
zoranbankovic at gmail dot com
13 年前
如果有人想直接在多维数组中添加斜杠,可以使用递归(按引用传递)函数,如下所示
<?php
function slashit(&$aray, $db_link)
{
foreach (
$aray as $key => &$value)
if(
is_array($value)) slashit($value, $link);
else
$aray[$key] = mysql_real_escape_string($value, $db_link);
}

// 测试:
$fruits = array (
"fruits" => array("a" => "or'ange", "b" => "ban'ana", "c" => "apple'"),
"numbers" => array(1, 2, 3, 4, 5, 6),
"holes" => array("fir'st", 5 => "sec'ond", "thir'd"),
"odma" => "jugo'slavija"
);

// 您必须建立数据库连接或可以使用 addslashes 代替 mysql_real_escape_string 并从函数定义中删除 $link

slashit($fruits, $dbLink);
echo
"<pre>"; print_r($fruits); echo "</pre>";
?>

// 输出
数组
(
[fruits] => Array
(
[a] => or\'ange
[b] => ban\'ana
[c] => apple\'
)

[numbers] => Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
[5] => 6
)

[holes] => Array
(
[0] => fir\'st
[5] => sec\'ond
[6] => thir\'d
)

[odma] => jugo\'slavija
)
Youssef Omar
14 年前
这是为了显示当您将对象 A 作为另一个对象 B 的属性传递时,通过另一个对象 B 更改对象 A 属性的影响。

<?php
// 要传递到另一个类作为对象的类数据
class A{
public
$info;
function
__construct(){
$this->info = "eeee";
}
}

// B 类用于更改 A obj 中的 info
class B_class{
public
$A_obj;

function
__construct($A_obj){
$this->A_obj = $A_obj;
}
public function
change($newVal){
$this->A_obj->info = $newVal;
}
}

// 从 A 创建数据对象
$A_obj = new A();
// 打印 info 属性
echo 'A_obj info: ' . $A_obj->info . '<br/>';

// 创建 B 对象并将我们上面创建的 A_obj 传递给它
$B_obj = new B_class($A_obj);
// 通过 B 对象打印 info 属性,以确保它具有相同的值“eeee”
echo 'B_obj info: ' . $B_obj->A_obj->info . '<br/>';

// 更改 info 属性
$B_obj->change('xxxxx');
// 通过 B 对象打印 info 属性,以确保它已将值更改为“xxxxxx”
echo 'B_obj info after change: ' . $B_obj->A_obj->info . '<br/>';
// 从 A_obj 打印 info 属性,以查看通过 B_obj 的更改是否影响了它
echo 'A_obj info: ' . $A_obj->info . '<br/>';

?>

结果

A_obj info: eeee
B_obj info: eeee
B_obj info after change: xxxxx
A_obj info: xxxxx
grayson at uiuc dot edu
19 年前
我发现引用中一个微妙的特性,导致了我的一个 PHP 应用程序中的错误。简而言之,如果一个对象将它的某个成员传递给一个接收引用的外部函数,那么该外部函数可以将该成员变成指向内存中匿名位置的引用。

为什么这是一个问题?后来,当您使用 $a = $b 复制对象时,副本和原始对象会共享内存。

解决方案:如果您想要一个使用引用来修改对象成员的函数,那么您的对象永远不应该直接将成员传递给该函数。它应该首先复制成员。然后将该副本传递给函数。然后将该副本的新值复制到原始对象的成员中。

以下是一些可以重现此功能并演示解决方法的代码。

function modify1 ( &$pointer_obj ){
$pointer_obj->property = 'Original Value';
}

function modify2 ( &$pointer_obj ){
$newObj->property = 'Original Value';
$pointer_obj = $newObj;
}

class a {
var $i; # 一个带有属性的对象

function corrupt1(){
modify1 ($this->i);
}

function doNotCorrupt1(){
$tmpi = $this->i;
modify1 ($tmpi);
$this->i = $tmpi;
}

function corrupt2(){
modify2 ($this->i);
}

function doNotCorrupt2(){
$tmpi = $this->i;
modify2 ($tmpi);
$this->i = $tmpi;
}

}

$functions = array ('corrupt1', 'corrupt2', 'doNotCorrupt1', 'doNotCorrupt2');

foreach ($functions as $func){

$original = new a;

### 使用四个 $functions 之一将一些数据加载到原始对象中
$original->$func();

$copy = $original;

$copy->i->property = "Changed after the copy was made.";

echo "\n{$func}: \$original->i->property = '" . $original->i->property . "'";
}

该脚本生成以下输出

corrupt1: $original->i->property = 'Changed after the copy was made.'
corrupt2: $original->i->property = 'Changed after the copy was made.'
doNotCorrupt1: $original->i->property = 'Original Value'
doNotCorrupt2: $original->i->property = 'Original Value'
jlaing at gmail dot com
20 年前
在尝试使用特殊的 $this 变量进行对象引用时,我发现这样做不可行
class foo {
function bar() {
...
$this =& $some_other_foo_obj;
}
}

如果您想模拟此功能,您必须遍历类的变量并像这样分配引用

$vars = get_class_vars('foo');
foreach (array_keys($vars) as $field) {
$this->$field =& $some_other_foo_obj->$field;
}

现在,如果您修改 $this 中的值,它们将在 $some_other_foo_obj 中被修改,反之亦然。

希望对某些人有所帮助!

p.s.
developer at sirspot dot com 关于对象引用的笔记似乎不正确。

$temp =& $object;
$object =& $temp->getNext();

与以下代码完全相同

$object =& $object->getNext();

当您将 $temp 引用到 $object 时,它所做的只是使 $temp 成为与 $object 相同内存的别名,因此执行 $temp->getNext(); 和 $object->getNext(); 实际上是在同一个对象上调用同一个函数。如果您不相信,可以尝试一下。
dallgoot
6 年前
经过一番头疼之后,这里有一个函数可以检查两个变量 $a,$b 之间,其中一个是否是对另一个的引用。
这意味着它们“指向”同一个值。
在以下版本上测试
PHP 7.2.2 (cli) (built: Jan 31 2018 19:31:17) ( ZTS MSVC15 (Visual C++ 2017) x64 )
希望有帮助...
<?php

function are_references(&$a, &$b){
$mem = $a; // 记忆
$a = uniqid ("REFERENCE???", true ); // 改变 $a
$same = $a === $b; // 比较
$a = $mem; // 恢复 $a
return $same;
}
echo
"*** 不同的变量和不同的值\n";
$a = "toto";
$b = "tata";

var_dump($a, $b, are_references($a, $b));
echo
"验证原始值: $a, $b\n";

echo
"*** 不同的变量,但相同的的值\n";
$a = "toto";
$b = "toto";

var_dump($a, $b, are_references($a, $b));
echo
"验证原始值: $a, $b\n";

echo
'*** $b 是 $a 的引用'."\n";
$a = "titi";
$b = &$a;

var_dump($a, $b, are_references($a, $b));
echo
"验证原始值: $a, $b\n";

echo
'*** $a 是 $b 的引用'."\n";
$b = "titi";
$a = &$b;

var_dump($a, $b, are_references($a, $b));
echo
"验证原始值: $a, $b\n";
?>
结果
*** 不同的变量和不同的值
string(4) "toto"
string(4) "tata"
bool(false)
验证原始值: toto, tata
*** 不同的变量,但相同的的值
string(4) "toto"
string(4) "toto"
bool(false)
验证原始值: toto, toto
*** $b 是 $a 的引用
string(4) "titi"
string(4) "titi"
bool(true)
验证原始值: titi, titi
*** $a 是 $b 的引用
string(4) "titi"
string(4) "titi"
bool(true)
验证原始值: titi, titi
mramirez (at) star (minus) dev (dot) com
18 年前
对于来自 Pascal 的 PHP 程序员,
在对象 Pascal(Delphi)中,
变量引用使用“absolute”关键字。

PHP 示例

<?php

global $myglobal;

$myglobal = 5;

function
test()
{
global
$myglobal;

/* 局部 */ $mylocal =& $myglobal;

echo
"局部: " . $mylocal . "\n";
echo
"全局: " . $myglobal . "\n";
}

test();

?>

Pascal 示例

program dontcare;

var myglobal: integer;

procedure test;
var mylocal ABSOLUTE myglobal;
begin
write("局部: ", mylocal);
write("全局: ", myglobal);
end;

begin
myglobal := 5;
test;
end.

顺便说一句,PHP 中用于局部变量的“local”关键字,
将会受到欢迎 :-)
zzo38
16 年前
您可以像指针一样创建引用。示例
<?php
$a
=6;
$b=array(&$a); // $b 是指向 $a 的指针
$c=array(&$b); // $c 是指向 $b 的指针
$d=7;
$c[0][0]=9; // $a 是 9
$c[0]=array(&$d); // $b 是指向 $d 的指针
$c[0][0]=4; // $d 是 4
$b=array(&$a); // $b 再次成为指向 $a 的指针
echo $a.$b[0].$c[0][0].$d; // 输出 9994
?>
这些指针甚至可以传递给函数或从函数返回,复制并存储在多个数组/变量/对象中等等。
nslater at gmail dot com
19 年前
除了“Francis dot a at gmx dot net” 提到的笔记之外,您通常不应该在 FOR 这样的控制结构中使用 sizeof() 或 count() 这样的函数,因为每次迭代都会重复计算相同的值。无论您是按值传递还是按引用传递,这都会极大地降低速度。

通常,最好在定义循环控制结构之前计算静态值。

示例

<?php

$intSize
= sizeof($arrData);

for(
$i = 0; $i < $intSize; $n++) {
// 做一些事情
}

?>
jasonpvp at gmail dot com
16 年前
在循环遍历多维数组时更改其值

$var=array('a'=>array(1,2,3),'b'=>array(4,5,6));

foreach ($var as &$sub) {
foreach ($sub as &$element) {
$element=$element+1;
}
}

var_dump($var);

------------------------------
产生
------------------------------
array(2) {
["a"]=>
array(3) {
[0]=>
int(2)
[1]=>
int(3)
[2]=>
int(4)
}
["b"]=>
array(3) {
[0]=>
int(5)
[1]=>
int(6)
[2]=>
int(7)
}
}
jszoja at gmail dot com
8 年前
注意另一个引用的引用。即使这样做可能也是不好的做法。

<?php
class Obj1 { public $name = 'Obj1'; }
class
Obj2 { public $name = 'Obj2'; }

$objects = [];
$toLoad = [ 'Obj1', 'Obj2' ];

foreach(
$toLoad as $i => $obj )
{
$ref = new $obj();
$objects[$i] =& $ref; // 对引用的引用
// $objects[$i] = $ref; // 这样可以工作
}

echo
$objects[0]->name;
// 输出 'Obj2' !
?>
info at fedushin dot ru
3 年前
支持引用数组

<?php
$x
= 1;
$y = 2;
$z = 3;

$arr = [&$x, &$y, &$z];

foreach(
$arr as &$item)
$item = 10;

var_dump($x, $y, $z);
?>

输出

int(10) int(10) int(10)
To Top