引用不是什么

如前所述,引用不是指针。这意味着,以下构造不会像您预期的那样工作

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

发生的情况是 $varfoo 中将绑定到调用者中的 $bar,但随后重新绑定到 $GLOBALS["baz"]。无法使用引用机制将调用范围内的 $bar 绑定到其他内容,因为 $bar 在函数 foo 中不可用(它由 $var 表示,但 $var 只有变量内容,而不是调用符号表中的名称到值的绑定)。您可以使用 返回引用 来引用函数选择的变量。

添加笔记

用户贡献笔记 13 个笔记

Andrew
15 年前
引用不是什么:引用。

引用是不透明的东西,就像指针一样,除了 A) 更智能,B) 指向 HLL 对象,而不是内存地址。PHP 没有引用。PHP 有一个创建 *别名* 的语法,别名是同一个对象的多个名称。PHP 有几个语法片段用于按 *引用* 调用和返回,这实际上只是意味着抑制复制。在本手册的“引用”部分中,没有任何引用。
匿名
16 年前
文本中给出的示例

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

说明(至少在我看来)为什么 = 和 & 应该写在一起作为一种新的替换运算符,而不是像在 C 中那样分开写,例如 $var = &$GLOBALS["baz"] ;

使用全新的术语

对我来说,这个函数的结果并不奇怪,因为 =& 意味着“将 $var 的“目标”从它所在的位置更改为与 $GLOBALS["baz"] 的目标相同”。它“曾经是”实际参数 $bar,但现在它将是全局变量 “baz”。

如果您只是删除替换中的 &,它将把 $GLOBALS["baz"] 的值放到 $var 的目标中,即 $bar(除非 $bar 已经是引用,那么值将放到该目标中)。

总结一下,= 替换“目标”的值; =& 更改目标。
bravo1romeo
6 年前
您可以将数组的值引用到另一个数组的值,
但是,如果您通过重新分配数组来更改数组,引用将不再适用,例如

<?php
$ref
= [1,2,3];
$c = count($ref);
$foo = ['A'];

for(
$i=0;$i<$c;$i++)
$foo[] =& $ref[$i];

print_r($foo);
print_r($ref);

$ref = [4,5,6];

print_r($foo);
print_r($ref);
?>

将输出
数组
(
[0] => A
[1] => 1
[2] => 2
[3] => 3
)
数组
(
[0] => 1
[1] => 2
[2] => 3
)
数组
(
[0] => A
[1] => 1
[2] => 2
[3] => 3
)
数组
(
[0] => 4
[1] => 5
[2] => 6
)

因此,如果您希望值仍然引用,您必须单独设置数组值,不要重新分配数组
<?php
$ref
= [1,2,3];
$c = count($ref);
$foo = ['A'];

for(
$i=0;$i<$c;$i++)
$foo[] =& $ref[$i];

print_r($foo);
print_r($ref);

$bar = [4,5,6];
foreach(
$bar as $i => $value)
$ref[$i] = $value;

print_r($foo);
print_r($ref);
?>

结果
数组
(
[0] => A
[1] => 1
[2] => 2
[3] => 3
)
数组
(
[0] => 1
[1] => 2
[2] => 3
)
数组
(
[0] => A
[1] => 4
[2] => 5
[3] => 6
)
数组
(
[0] => 4
[1] => 5
[2] => 6
)
leonardp122794 at gmail dot com
7 年前
我有点同意上面那位用户的说法,他认为 php 引用实际上比 JAVA 或 C++ 更像 c 指针。

原因如下。

它们的行为本质上与指针完全相同。

unset($x) 和 free(x) 之间的区别似乎是 unset() 和 free() 运算符之间的区别,而不是引用和指针本身之间的区别。

Free 释放堆上的内存。

Unset 只删除变量。

除此之外,我们在这里处理的是两个非常简单的构造。
briank at kappacs dot com
13 年前
我认为在分配对象时,术语让人感到困惑。

尝试像这样思考绑定和引用

<?php
# 代码:
$a = 5; $b =& $a; $c = new stdClass(); $d = $c;

# 背后符号表和值:
$global_names = array(
'a' => array('binding' => 0),
'b' => array('binding' => 0),
'c' => array('binding' => 1),
'd' => array('binding' => 2),
);
$values = array(
0 => array('type' => 'scalar', 'value' => 5),
1 => array('type' => 'objId', 'value' => 0),
2 => array('type' => 'objId', 'value' => 0)
);
?>

$a 绑定到(或引用,或引用)索引 0 处的值(标量 5)。
$b 绑定到与 $a 相同的东西 - 索引 0 处的值(标量 5)。
$c 绑定到索引 1 处的值(对象 ID 0)。
$d 绑定到索引 2 处的值(一个单独且不同的值,也引用对象 ID 0)。

当文档说明你不能在示例函数 foo 中将 $bar [重新] 绑定到其他东西时,这意味着你不能改变在我的伪引擎中是 $global_names['bar']['binding'] 的东西。你只能改变 $values[$names['var']['binding']](使用“$var =”;与 $values[$global_names['bar']['binding'] 引用的/绑定的相同值)或 $names['var']['binding'](使用“$var =&”)。

也考虑这段代码

<?php
$a
= 3; $b =& $a;
function
foo (&$c) { $c = new stdClass(); }
function
bar () { return new stdClass(); }
function &
fum () { return new stdClass(); }
if (!
is_object($a)) { echo "\$a does not initially refer to an object\n"; }
foo($b);
echo
"\$b ", ($a === $b)? "has not": "has", " been re-bound by foo\n";
if (
is_object($a)) { echo "\$a now contains an object identifier\n"; }
$b =& bar();
echo
"\$b ", ($a === $b)? "has not": "has", " been re-bound by bar\n";
$b =& fum();
echo
"\$b ", ($a === $b)? "has not": "has", " been re-bound by fum\n";
?>

其输出

$a does not initially refer to an object
$b has not been re-bound by foo
$a now contains an object identifier
$b has not been re-bound by bar
$b has been re-bound by fum

换句话说,值可以更改,但绑定不会(除了返回引用),正如所述。

对象标识符使对象“值”的行为类似于指针(但不像 C/C++,也不像引用)。
ansonyumo at email dot com
20 年前
断言“引用不像指针”有点令人困惑。

在示例中,作者展示了将引用分配给也是引用的形式参数如何不会影响实际参数的值。这正是 C 中指针的行为方式。唯一的区别是,在 PHP 中,你不需要解除对指针的引用才能获取值。

-+-+-
int bar = 99;

void foo(int* a)
{
a = &bar;
}

int main()
{
int baz = 1;
foo(&baz);
printf("%d\n", baz);
return 0;
}
-+-+-

输出将是 1,因为 foo 不会将值分配给解除引用的形式参数。相反,它在 foo 的范围内重新分配形式参数。

或者,
-+-+-
int bar = 99;

void foo(int* a)
{
*a = bar;
}

int main()
{
int baz = 1;
foo(&baz);
printf("%d\n", baz);
return 0;
}
-+-+-

输出将是 9,因为 foo 在分配之前取消了对形式参数的引用。

因此,虽然语法存在差异,但 PHP 引用实际上与 C 中的指针非常相似。

我同意 PHP 引用与 Java 引用非常不同,因为 Java 没有任何机制以这样的方式将值分配给引用,从而修改实际参数的值。
Anonymous
8 年前
有可能做一些类似于指针(如 C 中)的事情,例如,array(&$a) 是一个指向名为 $a 的变量的指针;此值可以作为值传递;它不是变量或别名或任何其他东西,而是一个实际的值。

然后,可以使用以下代码通过指针进行读写
<?php
function get($x) { return $x[0]; }
function
put($x,$y) { $x[0]=$y; }
?>
christian at kno dot at
22 年前
如上所述,引用不是指针。

以下示例显示了指针和引用之间的区别。

这段代码
<?
$b = 1;
$a =& $b;

print("<pre>");
print("\$a === \$b: ".(($a === $b) ? "ok" : "failed")."\n");
print("unsetting \$a...\n");
unset($a);
print("now \$a is ".(isset($a) ? "set" : "unset")." and \$b is ".(isset($b) ? "set" : "unset")."\n");
print("</pre>");

$b = 1;
$a =& $b;

print("<pre>");
print("\$a === \$b: ".(($a === $b) ? "ok" : "failed")."\n");
print("unsetting \$b...\n");
unset($b);
print("now \$a is ".(isset($a) ? "set" : "unset")." and \$b is ".(isset($b) ? "set" : "unset")."\n");
print("</pre>");
?>

将产生以下输出
---------
$a === $b: ok
unsetting $a...
now $a is unset and $b is set

$a === $b: ok
unsetting $b...
now $a is set and $b is unset
---------

所以你可以看到 $a 和 $b 是相同的 ($a === $b -> true),但是如果其中一个被取消设置,另一个不会受到影响。
ArticIce(Juice)
9 年前
考虑这块代码

<?php
$arr
= ['1', '2', '3', '4'];

foreach (
$arr as &$i) {}
echo
implode($arr, ', ')."\n";

foreach (
$arr as $i) {}
echo
implode($arr, ', ')."\n";
?>

这将输出
1, 2, 3, 4
1, 2, 3, 3

虽然看起来数组没有进行任何更改。

数组中的最后一项被覆盖,因为引用在第二次迭代中被副本替换。更详细地说,它首先被 1 覆盖,然后被 2、3 覆盖,然后再次被 3 覆盖。

在使用相同的变量名进行按引用迭代后,在按副本进行迭代时,请确保执行 unset($i)!
shuimuqingshu at gmail dot com
12 年前
我认为以下代码可以说明 PHP 引用和 C 指针之间的区别

在 PHP 中
<?php
$a
= 0;
$b = &a;
echo
$a; //0
unset($b); // 取消设置 $b
echo $a; //0 正常
?>

在 C 中
#include <stdio.h>
int main(int argc, char const *argv[]) {
int a = 0;
int* b = &a;

printf("%i\n", a); //0
free(b); // 释放 b
printf("%i\n", a); // 出现错误:*** 对象 0x7fff6350da08 错误:释放的指针未分配
}
Anonymous
14 年前
我理解这一点
PHP 中的引用就像在 C/C++ 中为自己的变量创建单个指针,并指向该变量(没有指针运算,我们无法获取内存中变量地址的编号)。

例如
<?php
$a
= 4;
$b = &$a;
$c = &$b;
echo
"$a - $b - $c<br>";
// 3 个指针 (a, b, c) 指向存储数字 4 的内存位置。
$c = 5;
echo
"$a - $b - $c<br>";
// 所有变量都等于 5;
unset($a);
$c = 6;
echo
"$a - $b - $c<br>";
//$a 不存在,但它只是一个指针(不是内存的实际部分),因此我们没有办法获取或更改它的值。
?>
----
当我们想要在 PHP 中创建一些“指针的指针”时,我们无法做到,因为这在 PHP 中是不可能的。我们需要一个指向另一个指针的指针来更改指针所指向的位置。在你的例子中,你只是在函数中改变了变量的值。(没有指针操作)
schultz __at__ widescreen __dot__ ch
20 年前
一个不太简单的解决方法......但仍然可行......玩得开心

class My{
var $value;

function get1(&$ref){
$ref[] =& $this;
}

function get2(&$ref){
$ref =& $this;
}

function get3(&$ref){
$ref = $this;
}
}

$m = new My();

$m->value = 'foo';
$m->get1($ref=array());
$m1 =& $ref[0];
$m1->value = 'bar';
echo "\n".'有效但很丑陋...';
echo "\n".' m:'. get_class($m) . '->value = '. $m->value;
echo "\n".' m1:'. get_class($m1) . '->value = '. $m1->value;

echo "\n".'无效,因为引用不是指针...';
$m->value = 'foo';
$m->get2($m2);
$m2->value = 'bar';
echo "\n".' m:'. get_class($m) . '->value = '. $m->value;
echo "\n".' m2:'. get_class($m2) . '->value = '. $m2->value;

$m->value = 'foo';
$m->get3($m3);
$m3->value = 'bar';
echo "\n".'无效,因为它被设置为副本';
echo "\n".' m:'. get_class($m) . '->value = '.$m->value;
echo "\n".' m3:'. get_class($m3) . '->value = '. $m3->value;
minhtrung2606 at gmail dot com
5 年前
<?php
function foo(&$var)
{
$var =& $GLOBALS["baz"];
}
foo($bar);
?>

让我们用另一种方式重写上面的代码片段

<?php
$bar
= &$var; // 此时,$bar 指向 $var 所指向的内容,即 NULL 或空。
$var = & $GLOBALS["baz"]; // 此时,$var 更改为指向全局变量 $baz 所指向的另一个内容。 但是 $bar 仍然指向 NULL 的内容。

预期结果: $bar 将保存 $var 的内容(现在是 $baz 的内容)
实际结果: $bar 保存 NULL 的内容或为空。 这就是 PHP 引用所做的事情
To Top