PHP Conference Japan 2024

返回引用

当您希望使用函数查找应将引用绑定到的变量时,返回引用很有用。**不要**使用按引用返回来提高性能。引擎会自动对此进行优化。只有在有正当的技术原因时才返回引用。要返回引用,请使用以下语法

<?php

class Foo
{
public
$value = 42;

public function &
getValue()
{
return
$this->value;
}
}

$obj = new Foo();
$myValue = &$obj->getValue(); // $myValue 是 $obj->value 的引用,值为 42
$obj->value = 2;
echo
$myValue; // 打印 $obj->value 的新值,即 2

?>
在这个例子中,getValue 函数返回的对象的属性将被设置,而不是副本,因为如果没有使用引用语法,它将是副本。

注意: 与参数传递不同,您必须在这两个地方都使用 & - 指示您要按引用返回,而不是副本,并指示应为 $myValue 执行引用绑定,而不是通常的赋值。

注意: 如果您尝试使用以下语法从函数返回引用:return ($this->value); 这将**无效**,因为您尝试按引用返回表达式的结果,而不是变量。您只能从函数按引用返回变量 - 而不是其他任何东西。

要使用返回的引用,必须使用引用赋值

<?php

function &collector()
{
static
$collection = array();
return
$collection;
}

$collection = &collector();
$collection[] = 'foo';

?>
要将返回的引用传递给另一个期望引用的函数,可以使用以下语法
<?php

function &collector()
{
static
$collection = array();
return
$collection;
}

array_push(collector(), 'foo');

?>

注意: 请注意 array_push(&collector(), 'foo'); 将**无效**,会导致致命错误。

添加注释

用户贡献的注释 18 条注释

Spad-XIII
16 年前
对下面 minikomp dot com 上的像素示例进行一些补充
<?php

function &func(){
static
$static = 0;
$static++;
return
$static;
}

$var1 =& func();
echo
"var1:", $var1; // 1
func();
func();
echo
"var1:", $var1; // 3
$var2 = func(); // 没有使用 & 的赋值
echo "var2:", $var2; // 4
func();
func();
echo
"var1:", $var1; // 6
echo "var2:", $var2; // 仍然是 4

?>
szymoncofalik at gmail dot com
13 年前
有时,您希望使用返回引用的函数返回 NULL,以指示元素链的结束。但是,这会生成 E_NOTICE。以下是如何防止此问题的小技巧

<?php
class Foo {
const
$nullGuard = NULL;
// ... 一些声明和定义
public function &next() {
// ...
if (!$end) return $bar;
else return
$this->nullGuard;
}
}
?>

通过这样做,您可以在没有通知的情况下执行类似的操作

<?php
$f
= new Foo();
// ...
while (($item = $f->next()) != NULL) {
// ...
}
?>

您也可以使用全局变量
global $nullGuard;
return $nullGuard;
stanlemon at mac dot com
17年前
我还没有看到任何人注意到PHP5中的方法链。当一个对象由PHP5中的方法返回时,它默认情况下是通过引用返回的,新的Zend Engine 2允许你从这些返回的对象中链式调用方法。例如,考虑以下代码

<?php

class Foo {

protected
$bar;

public function
__construct() {
$this->bar = new Bar();

print
"Foo\n";
}

public function
getBar() {
return
$this->bar;
}
}

class
Bar {

public function
__construct() {
print
"Bar\n";
}

public function
helloWorld() {
print
"Hello World\n";
}
}

function
test() {
return new
Foo();
}

test()->getBar()->helloWorld();

?>

注意我们是如何调用test()的,它不在一个对象上,但返回了一个Foo的实例,然后是Foo上的一个方法getBar(),它返回了一个Bar的实例,最后调用了它其中一个方法helloWorld()。熟悉其他解释性语言(例如Java)的人会识别出此功能。出于某种原因,此更改似乎没有得到很好的记录,因此希望有人会发现它有用。
obscvresovl at NOSPAM dot hotmail dot com
19年前
返回引用的示例

<?

$var = 1;
$num = NULL;

function &blah()
{
$var =& $GLOBALS["var"]; # 与global $var;相同;
$var++;
return $var;
}

$num = &blah();

echo $num; # 2

blah();

echo $num; # 3

?>

注意:如果你从函数中去掉&,第二个echo将是2,因为没有&,变量$num包含它的返回值,而不是它的返回引用。
sandaimespaceman at gmail dot com
16 年前
&b() 函数返回全局作用域中 $a 的引用。

<?php
$a
= 0;
function &
b()
{
global
$a;
return
$a;
}
$c = &b();
$c++;
echo
"
\$a:
$a
\$b:
$c
"
?>

它输出

$a: 1 $b: 1
fabian dot picone at gmail dot com
6年前
此注释似乎不适用于PHP 7

"注意:如果你尝试使用以下语法从函数返回引用:return ($this->value); 这将不起作用,因为你试图通过引用返回表达式的结果,而不是变量。你只能从函数中通过引用返回变量 - 而不是其他任何东西。从PHP 5.1.0开始,如果代码尝试返回动态表达式或 new 运算符的结果,则会发出 E_NOTICE 错误。"

以下代码在没有错误输出的情况下工作。与我没有在 $this-value 周围使用大括号的结果相同。

<?php

class foo {
public
$value = 42;

public function &
getValue() {
return (
$this->value);
}
}

$obj = new foo;
$myValue = &$obj->getValue();
$obj->value = 2;
echo
$myValue;
rwruck
18年前
关于在返回引用时使用括号的注释仅在尝试返回的变量本身不包含引用时才有效。

<?php
// 将返回引用
function& getref1()
{
$ref =& $GLOBALS['somevar'];
return (
$ref);
}

// 将返回一个值(并发出通知)
function& getref2()
{
$ref = 42;
return (
$ref);
}

// 将返回引用
function& getref3()
{
static
$ref = 42;
return (
$ref);
}
?>
civilization28 at gmail dot com
10年前
Zayfod 上面的示例很有用,但我认为它需要更多解释。应该说明的是,通过引用传递的参数可以更改为引用其他内容,从而导致后续对局部变量的更改不会影响传入的变量

<?php

function & func_b ()
{
$some_var = 2;
return
$some_var;
}

function
func_a (& $param)
{
# $param 在这里为 1
$param = & func_b(); # 在这里,引用被更改,并且
# "func_a (& $param)" 中的 "&"
# 完全不再生效。
# $param 在这里为 2
$param++; # 对 $var 没有影响。
}

$var = 1;
func_a($var);
# $var 在这里仍然为 1!因为引用已更改。

?>
benjamin dot delespierre at gmail dot com
13 年前
请记住,通过引用返回不适用于 __callStatic

<?php
class Test {
private static
$_inst;
public static function &
__callStatic ($name, $args) {
if (!isset(static::
$_inst)){
echo
"create";
static::
$_inst = (object)"test";
}
return static::
$_inst;
}

var_dump($a = &Test::abc()); // 打印 'create'
$a = null;
var_dump(Test::abc()); // 不打印,并且实例仍然存在于 Test::$_inst 中
?>
hawcue at yahoo dot com
20年前
在使用三元运算符条件?value1:value2 时要小心

请参阅以下代码

$a=1;
function &foo()
{
global $a;
return isset($a)?$a:null;
}
$b=&foo();
echo $b; // 显示 1
$b=2;
echo $a; // 显示 1(不是 2!因为 $b 获取了 $a 的副本)

要让 $b 成为 $a 的引用,请在函数中使用 "if..then.."。
anisgazig at gmail dot com
2年前
<?php

$a
= 9;
function &
myF(){
global
$a;
return
$a;
}

// 修改值之前
$func =& myF();
echo
"$a and $func";
echo
"\n";

// 修改值之后
$func++;
echo
"$a and $func";
php at thunder-2000 dot com
17年前
如果你想获取数组的一部分进行操作,可以使用此函数

function &getArrayField(&$array,$path) {
if (!empty($path)) {
if (empty($array[$path[0]])) return NULL;
else return getArrayField($array[$path[0]], array_slice($path, 1));
} else {
return $array;
}
}

使用方法如下

$partArray =& getArrayField($GLOBALS,array("config","modul1"));

您可以操作 $partArray,并且更改也会反映到 $GLOBALS 中。
zayfod at yahoo dot com
21 年前
文档此页的说明有一个小的例外情况。当您将通过引用传递的值赋值为返回引用的函数的结果时,您不必使用 & 来指示应该进行引用绑定。

考虑以下两个示例

<?php

function & func_b ()
{
$some_var = 2;
return
$some_var;
}

function
func_a (& $param)
{
# $param 在这里为 1
$param = & func_b();
# $param 在这里为 2
}

$var = 1;
func_a($var);
# $var 在这里仍然为 1!

?>

第二个示例按预期工作

<?php

function & func_b ()
{
$some_var = 2;
return
$some_var;
}

function
func_a (& $param)
{
# $param 在这里为 1
$param = func_b();
# $param 在这里为 2
}

$var = 1;
func_a($var);
# $var 在这里为 2,如预期

?>

(使用 PHP 4.3.0 的经验)
spidgorny at gmail dot com
14 年前
当返回在函数内部实例化的对象成员的引用时,对象会在返回时被销毁(这是一个问题)。查看代码更容易理解

<?php

class MemcacheArray {
public
$data;

...

/**
* 超级聪明的单行缓存读取和写入!
* 用法 $data = &MemcacheArray::getData(__METHOD__);
* 希望 PHP 会知道 $this->data 仍在使用
* 并将在数据更改后调用析构函数。
* 哎呀,情况并非如此。
*
* @return unknown
*/
function &getData($file, $expire = 3600) {
$o = new MemcacheArray($file, $expire);
return
$o->data;
}
?>

这里,析构函数在 return() 时被调用,并且引用变成了一个普通变量。

我的解决方案是在最终退出() 之前将对象存储在一个池中,但我不喜欢这样。还有其他想法吗?

<?php
protected static $instances = array();

function &
getData($file, $expire = 3600) {
$o = new MemcacheArray($file, $expire);
self::$instances[$file] = $o; // 防止对象过早销毁
return $o->data;
}
?>
Anonymous
10年前
我在使用一个通过引用传递的类方法时吸取了一个痛苦的教训。

简而言之,如果您在类中有一个在声明期间使用 & 符号初始化的方法,请不要在使用该方法时再使用 & 符号,例如 &$this->method();。

例如
<?php
class A {
public function &
hello(){
static
$a='';
return
$a;
}
public function
bello(){
$b=&$this->hello(); // 不正确。不要使用 & 符号。
$b=$this->hello(); // $b 是静态变量的引用。
}
?>
jpenna
4 年前
您可以设置通过引用返回的变量的值,无论是 `static` 函数变量还是对象的 `private` 属性(这非常危险 o.o)。

静态函数变量

<?php
function &func(){
static
$static = 0;
return
$static;
}

$var1 =& func();
echo
"var1:", $var1, "\n"; // 0
func();

$var1 = 90;
echo
"var1:", $var1, "\n"; // 90
echo "static:", func(), "\n"; // 90
?>

私有属性

<?php
class foo {
private
$value = 1;

public function &
getValue() {
return
$this->value;
}

public function
setValue($val) {
$this->value = $val;
}
}

$obj = new foo;
$myValue = &$obj->getValue(); // $myValue 是 $obj->value 的引用,值为 1。
echo $obj->getValue(); // 1
echo $myValue; // 1
$obj->setValue(5);
echo
$obj->getValue(); // 5
echo $myValue; // 5
$myValue = 1000;
echo
$obj->getValue(); // 1000
echo $myValue; // 1000
?>
contact at infopol dot fr
20年前
关于在非引用数组中嵌入返回引用的说明

<?
$foo;

function bar () {
global $foo;
$return = array();
$return[] =& $foo;
return $return;
}

$foo = 1;
$foobar = bar();
$foobar[0] = 2;
echo $foo;
?>

结果为“2”,因为引用被复制了(非常巧妙)。
willem at designhulp dot nl
19年前
PHP5 和 PHP4 在引用方面存在重要差异。

假设您有一个类,其中有一个名为“get_instance”的方法,用于获取对现有类及其属性的引用。



<?php
class mysql {
function
get_instance(){
// 检查对象是否存在
if(empty($_ENV['instances']['mysql'])){
// 还没有对象,创建一个对象
$_ENV['instances']['mysql'] = new mysql;
}
// 返回对象的引用
$ref = &$_ENV['instances']['mysql'];
return
$ref;
}
}
?>

现在要获取现有的对象,可以使用
mysql::get_instance();

虽然这在 PHP4 和 PHP5 中都能工作,但在 PHP4 中,所有数据都会丢失,就像它是一个新对象一样,而在 PHP5 中,对象中的所有属性都将保留。
To Top