通过删除在发生按引用传递的函数调用(即函数定义使用 &)上包含引用符号的功能,代码的可读性会降低,因为必须查看函数定义才能知道传递的变量是按引用传递还是按值传递(即可能被修改)。如果函数调用和函数定义都需要引用符号(即 &),则可读性会提高,并且还会减少代码本身中意外错误的可能性。现在在 5.4.0 中全面使用致命错误迫使每个人都使用可读性较差的代码。也就是说,函数仅仅使用变量,还是可能修改它……现在我们必须找到函数定义并实际查看它才能知道,而之前我们可以立即知道意图。
您可以按引用将变量传递给函数,以便函数可以修改该变量。语法如下
<?php
function foo(&$var)
{
$var++;
}
$a=5;
foo($a);
// $a 在这里为 6
?>
注意: 在函数调用上没有引用符号 - 只有在函数定义上才有。仅函数定义足以正确地按引用传递参数。
以下内容可以按引用传递
foo($a)
从函数返回的引用,例如
<?php
function foo(&$var)
{
$var++;
}
function &bar()
{
$a = 5;
return $a;
}
foo(bar());
?>
不应按引用传递任何其他表达式,因为结果未定义。例如,以下按引用传递的示例无效
<?php
function foo(&$var)
{
$var++;
}
function bar() // 注意缺少 &
{
$a = 5;
return $a;
}
foo(bar()); // 生成通知
foo($a = 5); // 表达式,而不是变量
foo(5); // 生成致命错误
class Foobar {}
foo(new Foobar()) // 从 PHP 7.0.7 开始生成通知
// 通知:只有变量才能按引用传递
?>
通过删除在发生按引用传递的函数调用(即函数定义使用 &)上包含引用符号的功能,代码的可读性会降低,因为必须查看函数定义才能知道传递的变量是按引用传递还是按值传递(即可能被修改)。如果函数调用和函数定义都需要引用符号(即 &),则可读性会提高,并且还会减少代码本身中意外错误的可能性。现在在 5.4.0 中全面使用致命错误迫使每个人都使用可读性较差的代码。也就是说,函数仅仅使用变量,还是可能修改它……现在我们必须找到函数定义并实际查看它才能知道,而之前我们可以立即知道意图。
<?php
// PHP >= 5.6
// 在这里,我们使用 'use' 运算符在函数的作用域内创建变量。虽然看起来新创建的变量与函数外部的 '$x' 有某种关系,但实际上我们是在函数内部创建了一个 '$x' 变量,它与函数外部的 '$x' 变量没有任何关系。我们说的是相同的名称,但内存中的内容位置不同。
$x = 10;
(function() use ($x){
$x = $x*$x;
var_dump($x); // 100
})();
var_dump($x); // 10
// 现在,使用引用 (&) 的魔力发生了。现在我们实际上正在访问函数作用域之外的 '$y' 变量的内容。我们在函数内对变量 '$y' 执行的所有操作都将在该函数的相同作用域之外反映出来。记住这在函数式范式中将是一个不纯函数,因为我们正在按引用更改变量的值。
$y = 10;
(function() use (&$y){
$y = $y*$y;
var_dump($y); // 100
})();
var_dump($y); // 100
?>
注意 unset() 会破坏引用
$x = 'x';
change( $x );
echo $x; // 输出 "x" 而不是 "q23" ---- 删除 unset(),输出为 "q23" 而不是 "x"
function change( & $x )
{
unset( $x );
$x = 'q23';
return true;
}
按引用传递的参数可以具有默认值。
您可以使用 func_num_args() 找出变量是否确实被传递。
<?php
function refault( & $ref = '我需要被计算吗?'){
echo '参数数量: '. func_num_args()."\n";
echo "原始值: {$ref}\n";
if( func_num_args() > 0 ) $ref = '是的,计算结果代价很高: ' . sleep(1);
else $ref = '否。';
echo "新值: {$ref}\n";
}
$result = '我需要被计算吗?';
refault( $result );
echo "结果: {$result}\n";
// 参数数量: 1
// 原始值: 我需要被计算吗?
// 新值: 是的,计算结果代价很高: 0
// 结果: 是的,计算结果代价很高: 0
refault();
// 参数数量: 0
// 原始值: 我需要被计算吗?
// 新值: 否。
?>
在类中,通过引用传递不存在的数组元素将被添加到数组中,其值为 null。与普通函数相比,这改变了函数的行为,从抛出错误变成了在引用的数组中创建一个新的(null)条目,并赋予其一个新的键。
<?php
class foo {
public $arr = ['a' => 'apple', 'b' => 'banana'];
public function normalFunction($key) {
return $this->arr[$key];
}
public function &referenceReturningFunction($key) {
return $this->arr[$key];
}
}
$bar = new foo();
$var = $bar->normalFunction('beer'); //注意错误。未定义索引 beer
$var = &$bar->referenceReturningFunction('beer'); // 无错误。$bar 的值现在为 null
var_dump($bar->arr);
/**
[
"a" => "apple",
"b" => "banana",
"beer" => null,
],
*/
?>
这绝不是一个“错误” - 框架按设计工作,但需要仔细思考才能弄清楚发生了什么。PHP7.3