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

时间:2016-01-21 18:50:08

标签: php pointers pass-by-reference

设置

我从一个我经常用于自定义项目的开源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,返回的值将在更改时更新静态存储。

问题

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

我对指针的理解是,如果我返回指针,php会自动将变量强制转换为指针$a = &$b,使$a指向$b的值。

问题

为什么呢?如果函数返回一个引用,为什么我必须在函数调用之前使用引用运算符?

2 个答案:

答案 0 :(得分:2)

来自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解释器。函数定义中的第一个用法是返回引用,第二个用于通过引用而不是值赋值给赋值。

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

编辑:正如下面的@ringø所指出的那样,它不会返回一个内存地址,而是一个将被视为副本的对象(技术上是写时复制)。

答案 1 :(得分:2)

PHP doc解释了如何使用以及为什么返回引用的函数。

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

这不会起作用(语法错误)

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

这并没有按预期工作(没有返回参考)

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

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

关于为什么的问题......似乎并不是一致的答案。

  • 如果缺少&中的一个,那么PHP将数据视为不是引用(例如返回数组),而不会发出任何警告
  • here与返回引用的函数相关的一些奇怪之处

PHP在这些年中不断发展,但仍然继承了一些最初的糟糕设计选择。这似乎是其中之一(这种语法容易出错,因为人们可能很容易错过一个& ...而且前面没有警告......;为什么不直接返回像return &$var;这样的引用?) 。 PHP取得了一些进展,但still,设计不良的痕迹存在。

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

  

不要使用按引用返回来提高性能。引擎将自动对其进行自动优化。只有在有正当技术理由的情况下才能返回引用。

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