为什么我必须在函数调用中使用引用运算符 (&)?

Why do I have to use the reference operator (&) in a function call?

设置

我正在从我经常用于自定义项目的开源 CMS 中借用一个功能。

它的用途对于这个问题并不重要,但如果您想知道它是一个旨在减少数据库查询的简单静态缓存。我可以在一页加载中调用 getObject 10 次,而不必担心访问数据库 10 次。

代码

该函数的简化版本如下所示:

function &staticStorage($name, $default_value = NULL)
{
  static $data = array();
  if (isset($data[$name])
  {
    return $data[$name];
  }
  $data[$name] = $default_value;
  return $data[$name];
}

这个函数会像这样被调用:

function getObject($object_id)
{
  $object = &staticStorage('object_' . $object_id);
  if ($object)
  {
    return $object;
  }

  // This query isn't accurate but that's ok it's not important to the question.
  $object = databaseQuery('SELECT * FROM Objects WHERE id = @object_id', 
                          array('@object_id => $object_id'));
  return $object;
}

想法是,一旦我调用 static_storage,returned 值将在更改时更新静态存储。

问题

我感兴趣的是行 $object = &staticStorage('object_' . $object_id); 注意函数前面的 &staticStorage 函数 return 已经是一个引用,所以我最初没有在函数调用之前包含引用运算符。但是,如果函数调用之前没有引用,它就无法正常工作。

我对指针的理解是如果我 return 一个指针 php 会自动将变量转换为指针 $a = &$b 会导致 $a 指向的值$b.

问题

为什么?如果函数 return 是引用,为什么我必须在函数调用之前使用引用运算符?

来自 PHP 文档

Note: Unlike parameter passing, here you have to use & in both places - to indicate that you want to return by reference, not a copy, and to indicate that reference binding, rather than usual assignment, should be done for $myValue.

http://php.net/manual/en/language.references.return.php

基本上,它是为了帮助 php 解释器。函数定义中第一个使用是return引用,第二个是通过引用而不是值绑定到赋值。

通过将 & 放在函数声明中,函数将 return 一个 return 值的内存地址。除非另有明确说明,否则在获取此内存地址时,赋值会将值解释为 int,这就是赋值运算符需要第二个 & 的原因。

编辑:正如下面@ri​​ngø所指出的,它不是return内存地址,而是一个将被视为副本的对象(技术上copy-on-write).

PHP doc 解释了 return 引用的函数的使用方法和原因。

在您的代码中,getObject() 函数还需要一个 &(以及调用),否则引用将丢失,数据虽然可用,但基于 PHP copy-on-write(returned 数据和源数据都指向相同的实际数据,直到其中一个发生变化 => 两个数据块具有不同的生命周期)

这行不通(语法错误)

$a = array(1, 2, 3);
return &$a;

这没有按预期工作(没有参考 returned)

$a = array(1, 2, 3);
$ref = &$a;
return $ref;

并且没有像您所说的那样将 & 添加到函数调用中,也没有引用 returned。

关于为什么的问题...似乎没有一致的答案。

  • 如果缺少 & 之一 PHP 将数据视为不是引用(例如 returning 数组),没有任何警告
  • here 一些与函数相关的奇怪之处 returning 引用

PHP 经过多年的发展,但仍然继承了一些最初糟糕的设计选择。这似乎是其中之一(这种语法很容易出错,因为人们可能很容易错过一个 &... 并且没有提前警告...;另外为什么不直接 return 像 [=17 这样的参考=]?)。 PHP 取得了一些进展,但 still,设计不佳的痕迹依然存在。

您可能也对上面链接的文档的这一章感兴趣

Do not use return-by-reference to increase performance. The engine will automatically optimize this on its own. Only return references when you have a valid technical reason to do so.

最后,最好不要过多地寻找 C 中的指针和 PHP 引用之间的等价性(Perl 在这方面比 PHP 更接近)。 PHP 在指向数据的实际指针与变量和引用之间添加一层,而不是指向该层而不是实际数据。但是引用不是指针。如果 $a 是一个数组并且 $b 是对 $a 的引用,则使用 $a$b 访问数组是等效的。没有 dereference 语法,例如 C 中的 *$b$b 应该被视为 $a 的别名。这也是函数只能 return 引用变量的原因。