PHP Conference Japan 2024
添加注释

用户贡献的注释 34 条注释

SymmetricDesigns dot com 的 Dave
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
)
hkmaly at bigfoot dot com
20 年前
PHP 似乎在引用方面存在问题,例如它无法正确处理循环引用或正确释放具有多个引用的结构。参见 http://bugs.php.net/?id=30053.

我对此有很大的问题,我希望 PHP 的某个人能在手册中添加适当的警告和解释,如果他们无法修复它。
alexander at gamerev dot org
10 年前
简而言之,这是一个关于引用是什么的示例

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

echo
$foo;
?>

上面的示例将输出值 6,因为 $bar 引用 $foo 的值,因此,当更改 $bar 的值时,您也会更改 $foo 的值。
gnuffo1 at gmail dot com
14 年前
如果您想知道特定变量的引用计数,那么这里有一个函数可以使用 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() 通过减去这些额外的引用来考虑这些额外的引用,以获得返回值。

在处理通过引用赋值(=&)的变量时,它甚至更令人困惑,无论是在赋值的右侧还是左侧,因此,上述函数实际上并不适用于此类变量。我更倾向于在对象实例中使用它。

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

我只在 5.3 版本上测试过这个;由于 `debug_zval_dump()` 的性质,在其他版本上的结果可能完全不同。
php at REMOVEMEkennel17 dot co dot uk
19 年前
我在这篇文章中找到一个关于 PHP4 中引用如何工作(以及一些常见的陷阱)非常有用的总结:http://www.obdev.at/developers/articles/00002.html

它处理一些微妙的情况,我推荐给任何在引用方面有困难的人。
nathan
20 年前
在提到 PHP4 自动创建引用的帖子中,这似乎*不*适用于对象。

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

“注意:不使用 & 运算符会导致创建对象的副本。如果在类中使用 $this,它将对类的当前实例进行操作。不使用 & 的赋值将复制实例(即对象),而 $this 将对副本进行操作,这并不总是想要的。通常,由于性能和内存消耗问题,您希望使用单个实例。”
midir
15 年前
这是一篇优秀的杂志文章(PDF 格式),详细解释了 PHP 引用机制的内部原理:http://derickrethans.nl/files/phparch-php-variables-article.pdf

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

它是为 PHP 4 编写的,但仍然适用。唯一的区别在于 PHP 5 如何处理对象:按值传递对象变量只会复制指向对象的内部指针。只有在显式使用 clone 关键字时,PHP 5 中的对象才会被复制。
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
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
marco at greenlightsolutions dot nl
17 年前
我最近遇到一个问题,数组复制导致其中一个元素的引用复制,而不是克隆。示例代码

<?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 内部工作原理的特殊性,如果对数组的单个元素进行引用,然后复制数组(通过赋值或在函数调用中按值传递),则引用将作为数组的一部分被复制。这意味着对任一数组中任何此类元素的更改都将在另一个数组中(以及其他引用中)被复制,即使数组具有不同的作用域(例如,一个在函数内部,另一个是全局的)!在复制时没有引用的元素,以及在数组复制后分配给这些其他元素的引用,将表现正常(即独立于另一个数组)。"

但是,这段话似乎在某个时候从该页面中删除了,可能是因为它有点模糊。评论部分似乎是适合放置此内容的地方。
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。
某人
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() 将在此处显示 &
)

// 以上由 SymmetricDesign.com 的 Dave 提出 //
// 以下是我对这个简单问题的看法。//

这是一个普通的引用问题。

当你获得某个变量内存的引用时。
这个变量指的是“内存本身”。(在上面的例子中,这将是 -> $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 年前发布,但我只想澄清它不是一个错误。

如果我的笔记中有什么问题,请在上面注明。
[email protected]
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;
}
?>
[email protected]
17 年前
(v5.1.4)
var_dump 一个很酷的功能是它显示哪些变量是引用(在转储数组时),用 '∫' 表示整数/null,用 '&' 表示布尔值/双精度浮点数/字符串/数组/对象。我不知道为什么符号会有所不同。
玩弄之后,我发现了一种更好的实现分离的方法(偶然发现的)。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
}*/
?>

要使 detach 工作,需要在函数声明中使用 '&',并在每次调用时都使用它。

当你知道一个变量是引用,并且想要赋值一个新值而不会影响引用该内存块的其他变量时,可以使用此方法。你可以用一个新的常量值、变量或新的引用来初始化它,所有这些都在一步完成。
[email protected]
18年前
除了 '[email protected]' 关于 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 = $v1;
unset(
$v1);
$v1 = $detach;

// 更优雅的解除引用,但速度较慢
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中不存在“对象引用”这样的概念,但通过解除引用,可以实现类似的效果。

希望解除引用,或类似的机制,将来能成为PHP语言的内置特性。
jw at jwscripts dot com
20 年前
在没有先unset的情况下,重新使用之前是引用的变量,会导致意想不到的行为。

以下代码:

<?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
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`变量中访问。希望对大家有所帮助!
Ed
18年前
回复Slava Kudinov:你的脚本在通过引用传递时运行时间较长的唯一原因是,你根本没有修改传递给函数的数组。如果你修改了数组,执行时间的差异将会小得多。事实上,如果只是略微修改,通过引用传递会更快。
shooo dot xz at gmail dot com
11年前
嗨,我研究了一段时间引用相关的东西。
以下是我的一些发现。

问题:通过列排序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 年前
我不知道这是否是bug(我使用的是PHP 5.01),但在数组上使用引用时应该小心。
我有一个for循环,速度非常慢,我花了一些时间才发现大部分时间都浪费在了每次循环中的`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
17 年前
我必须说,理解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;

?>

假设我们将10MB的数据POST到这个PHP文件,PHP将如何处理内存?

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

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

如果您出于学习目的而选择忽略对这两种传递参数方法之间差异进行基准测试的明显无意义之处,则需要在将数据传递给函数时修改数据才能获得更准确的结果。
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) 如果需要在函数内部更改某些内容而不影响原始副本,则不要按引用传递它,而是传递需要更改的最小实际部分,而不是例如传递一个巨大的数组,其中只有一个小的整数将被更改。

或者更短的版本:只有在需要引用原始副本时才按引用传递内容!(并且当您只需要更改它们的一小部分时,不要传递巨大的数组或长字符串!)
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中修改,反之亦然。

希望这对某些人有所帮助!

附言:
sirspot dot com 的开发人员关于对象引用的说明在我看来似乎不正确。

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

与以下操作完全相同

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

当您将$temp引用到$object时,它所做的只是使$temp成为与$object相同内存的别名,因此执行$temp->getNext(); 和$object->getNext();是在同一个对象上调用相同的函数。如果您不相信我,请尝试一下。
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'!
?>
zoranbankovic at gmail dot com
14 年前
如果有人想直接在多维数组中添加斜杠,可以使用像这样的递归(按引用传递)函数
<?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
)
mramirez (at) star (minus) dev (dot) com
19 年前
对于来自Pascal的PHP程序员,
在Object 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”关键字,
可能会受到欢迎 :-)
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++) {
// 执行操作
}

?>
Youssef Omar
14 年前
这部分展示了当对象A作为对象B的一个属性传递时,通过对象B改变对象A属性的影响。

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

// B类用于更改A对象中的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属性,确保其值已更改为'xxxxx'
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
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)
}
}
grayson at uiuc dot edu
19 年前
我发现引用一个细微的特性导致我的一个PHP应用程序出现bug。简而言之,如果一个对象将其成员传递给一个以引用作为参数的外部函数,则外部函数可以将该成员变成对内存中匿名点的引用。

为什么这是一个问题?稍后,当您使用$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'
To Top