【问题标题】:Do I need to use the ampersand in PHP 5.5.X and above anymore?我是否需要在 PHP 5.5.X 及更高版本中使用 & 符号?
【发布时间】:2013-11-19 19:08:11
【问题描述】:

我在各处都收到了不同的信号。

我是否使用和号通过引用传递变量?

以下链接似乎告诉我它已被弃用且不再需要:
http://gtk.php.net/manual/en/html/tutorials/tutorials.changes.references.html

但是像这样的话题让我想知道:
Call-time pass-by-reference deprecated?
PHP and ampersand

让我以我的问题为例。

如果我创建一个函数,使用 PHP 5.5.5:

function recurring_mailer_form($form, $form_state) 
{

}

是否与:

function recurring_mailer_form($form, &$form_state) 
{

}

?

【问题讨论】:

标签: php pass-by-reference ampersand


【解决方案1】:

不,那些不一样。 PHP 5.4+ 只是在调用时通过检查声明来检测调用函数时是否需要引用。

所以不,不推荐使用,因为如果这是您的预期用途,您需要在函数声明中使用引用运算符。

【讨论】:

  • Any 版本的 PHP 在调用时根据声明检测是否需要引用。不同之处在于,在 PHP 5.4 之前,您可以强制通过引用传递一个变量尽管函数声明。
【解决方案2】:

不,不是。

  • 对象始终作为引用自动传递(信息!参见下文了解更多重要信息!)

  • 将参数声明为引用必须发生在函数定义中:

    function test(&$var) {}
    

    不是在调用它时:

    // wrong
    $var = '123';
    test(&$var);
    


如果像往常一样传递对象,则可以更改对象的状态(属性)。
假设$obj 是类TestClass 的一个实例,它包含一个名为hello (click here for a full sample at Ideone.com) 的成员变量:
function modify($obj) { $obj->hello = 'world (modified)!'; }

$obj->hello = 'world';
modify($obj);
var_dump($obj->hello);  // outputs "world (modified!)"

这应该是不言自明的。现在,使用相同的代码,但为$obj 分配另一个值,而不是修改对象的状态导致不修改 (→ Ideone.com):

function modify($obj) { $obj = 42; }
// ...
var_dump($obj->hello);  // outputs "world"

只有明确地接受参数作为参考,我们才能完全改变变量的内容(→ Ideone.com):

function modify(&$obj) { $obj = 42; }
// ...
var_dump($obj);         // outputs "42"

【讨论】:

  • “对象总是作为引用自动传递”——这不太正确(尽管手册偶尔会这样说)。如果通过引用传递变量,则可以分配给该变量本身;如果您按值传递,则不能。但是,按值传递对象确实允许您使用-> 运算符等操作对象
  • @IMSoP 感谢您的评论!我更新了我的答案。
  • 好简洁的例子 :) 人们经常忽略修改对象和修改变量之间的区别。
【解决方案3】:

不同的文章似乎在说不同的事情的原因是它们在谈论不同类型的传递引用。

决定一个参数是否应该通过引用传递的主要是函数签名本身,它的基本原理自 PHP 4 以来没有改变。考虑这个例子:

function foo( $by_value, &$by_reference ) { /* ... */ }

$a = 1; $b = 2;
foo( $a, $b );

这里,外部变量$a 按值传递给函数,就好像它被分配为$by_value = $a; - 更改为$by_value 不会影响$a。然而,变量$b 正在通过引用传递;就像$by_reference =& $b; 形式的赋值一样,这意味着有一个变量被两个名称引用,对一个变量的任何赋值都将作为对两者的赋值。

如果您按值传递“普通”值(字符串、数字或数组),则其值只是复制到新变量中。 从 PHP 5 开始:但是,如果您按值传递对象,则会发生一些稍微不同的事情 - 复制的“值”只是指向同一对象的指针。这意味着如果$a 是一个对象,您可以调用$by_value->some_property = 42; 并且$a->some_property 也将是42。但是,如果您为$by_value 分配了一些新值,它仍然不会影响$a

直到 PHP 5.4,还有一个额外的方法来通过引用传递参数,即在调用时“强制”引用行为 /em>。这意味着您可以在foo() 函数中编写foo(&$a, &$b); 并“捕获”对$by_value 所做的更改。依靠这个通常是一个坏主意,所以它被删除了。 (它登陆 5.4 是因为它打算在 PHP 6 中删除,但该项目被无限期搁置,较小的更改登陆 5.3 和 5.4)。

最后,函数可以通过引用返回一个变量(如discussed in the manual here)。这有点繁琐,因为它实际上需要您将& 放在两个 位置:在函数声明的开头,说return 应该意味着“返回此变量引用”而不是“返回这个值”;在调用它的代码中,为该引用分配一个变量,而不仅仅是复制它的值。这是一个愚蠢的例子,它结合了引用参数和引用返回(两者不必放在一起,这只是一个例子):

function &bar(&$some_param) { return $some_param; }
$a = 1;
$b =& bar($a);
// $b and $a now point at the same variable, not just the same value
// it was passed into and out of a function, and assigned to a new variable, 
// but all those operations were by reference

请注意,许多人错误地认为通过引用传递变量会给他们带来性能优势,这通常是他们使用调用时传递引用的唯一原因。这实际上通常是错误的,因为支持 PHP 的 Zend 引擎使用一种称为“写入时复制”的技术来保留多个变量,这些变量恰好具有指向同一块内存的相同值,即使它们没有绑定为参考。事实上,由于引擎跟踪哪些变量处于写时复制状态的方式,引用赋值通常击败这种优化。

【讨论】:

  • 关于性能的最后一段很重要,我来这里是为了寻找什么。您能否为这些结论提供一些参考资料?
  • @T.BrianJones 如果我想到在哪里可以找到一些好的文章,我会添加它们。如果您想四处搜索,请尝试搜索“zval”和“copy on write”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-11-13
  • 2016-03-28
  • 2020-03-30
  • 1970-01-01
  • 2015-05-10
  • 2023-03-03
  • 1970-01-01
相关资源
最近更新 更多