就像一个人有两个不同的名字。
PHP 中的引用是一种通过不同的名称访问相同变量内容的方法。它们不像 C 指针;例如,您不能使用它们执行指针算术运算,它们不是实际的内存地址,等等。请参阅引用不是什么以获取更多信息。相反,它们是符号表别名。请注意,在 PHP 中,变量名和变量内容是不同的,因此相同的内容可以具有不同的名称。最接近的类比是 Unix 文件名和文件 - 变量名是目录条目,而变量内容是文件本身。引用可以比作 Unix 文件系统中的硬链接。
与 C 不同,PHP 引用不被视为预解除引用的指针,而是完整的别名。
它们正在为其创建别名(“引用”)的数据在所有对它的引用都移除之前不会被垃圾回收。
“常规”变量本身被视为引用,并且出于垃圾回收的目的,它们与使用 =& 赋值的变量没有区别。
以下示例提供了说明。
1) 当被视为包含值的变量时,引用按预期的方式工作。但是,它们实际上是引用原始数据的对象。
<?php
var = "foo";
$ref1 =& $var; // 新的对象,引用 $var
$ref2 =& $ref1; // 直接引用 $var,而不是 $ref1!!!!!
echo $ref; // >foo
unset($ref);
echo $ref1; // >Notice: Undefined variable: ref1
echo $ref2; // >foo
echo $var; // >foo
?>
2) 当通过引用访问时,原始数据在所有对它的引用都移除之前不会被移除。这包括引用和未使用 & 运算符赋值的“常规”变量,并且出于垃圾回收的目的,这两者之间没有区别。
<?php
$var = "foo";
$ref =& $var;
unset($var);
echo $var; // >Notice: Undefined variable: var
echo $ref; // >foo
?>
3) 要删除原始数据而不删除所有对它的引用,只需将其设置为 null。
<?php
$var = "foo";
$ref =& $var;
$ref = NULL;
echo $var; // 值为 NULL,因此不打印任何内容
echo $ref; // 值为 NULL,因此不打印任何内容
?>
4) 将数据放入数组也被视为向其添加一个引用,用于垃圾回收。
有关更多信息,请参阅https://php.net/manual/en/features.gc.refcounting-basics.php
以下三个代码片段显示了在不同情况下使用标量变量、数组和对象中的引用的效果。
在任何情况下,如果您坚持引用是变量的别名的概念,则结果都是预期的。在通过引用赋值后(无论 $a =& $b 还是 $b =& $a),两个变量名都指向同一个变量。
带标量的引用
<?php
/*
引用是同一变量的别名
*/
$a = 1;
$b =& $a;
$b = 2;
echo "$a,$b\n"; // 2,2
$a = 3;
echo "$a,$b\n"; // 3,3
// 变量可以在赋值之前绑定
$c =& $d;
$c = 4;
echo "$c,$d\n"; // 4,4
?>
带数组的引用
<?php
/*
数组元素引用标量变量
*/
$a = 1;
$b = 2;
$c = array(&$a, &$b);
$a = 3;
$b = 4;
echo "c: $c[0],$c[1]\n"; // 3,4
$c[0] = 5;
$c[1] = 6;
echo "a,b: $a,$b\n"; // 5,6
/*
数组之间的引用
*/
$d = array(1,2);
$e =& $d;
$d[0] = 3;
$d[1] = 4;
echo "e: $e[0],$e[1]\n"; // 3,4
$e[0] = 5;
$e[1] = 6;
echo "d: $d[0],$d[1]\n"; // 5,6
$e = 7;
echo "d: $d\n"; // 7 ( $d 不再是数组,而是一个整数 )
/*
使用 foreach 结构迭代引用数组
*/
$a = 1;
$b = 2;
$f = array(&$a,&$b);
foreach($f as $x) // 如果 $x 按值赋值,则不会更改引用的变量。
$x = 3;
echo "a,b: $a,$b\n"; // 1,2
foreach($f as &$x) // 如果 $x 按引用赋值,则会更改引用的变量。
$x = 3;
echo "a,b: $a,$b\n"; // 3,3
// 请注意,循环结束后,$x 仍然引用 $f[1],因此也引用 $b
$x = 4;
echo "a,b: $a,$b\n"; // 3,4 ( $b 受影响 )
// 为了避免上述副作用,建议取消设置 x,将其与 $f[1] 和 $b 断开链接
unset($x);
$x = 5;
echo "a,b: $a,$b\n"; // 3,4 ( $b 不受影响 )
?>
对象引用
<?php
/*
对象属性引用标量变量
*/
$a = 1;
$b = new stdClass();
$b->x =& $a;
$a = 2;
echo "b->x: $b->x\n"; // 2
$b->x = 3;
echo "a: $a\n"; // 3
/* 对象之间的引用 */
$c = new stdClass();
$c->x = 1;
$d =& $c;
$d->x = 2;
echo "c->x: $c->x\n"; // 2
$d = new stdClass();
$d->y = 3;
echo "c->y: $c->y\n"; // 3
echo "c->x: $c->x\n"; // 未定义属性: stdClass::$x
?>