在PHP中使用引用

时间:2010-06-03 00:27:58

标签: php pass-by-reference parameter-passing pass-by-value

我问这个问题,因为我了解到在编程和设计中,你必须有充分的理由做出决定。我是PHP学习者,我在这里的十字路口,我使用简单的增量试图得到我要求的东西。我肯定不会在这里开始讨论引用的优缺点,但是当涉及到php时,这是更好的编程实践:

function increment(&$param) {
      ++$param;
}

VS

function increment($param){
 return ++$param;
}

$param = increment($param);

8 个答案:

答案 0 :(得分:10)

首先,references are not pointers

我尝试了@John在他的回答中给出的代码,但我得到了奇怪的结果。事实证明microtime()返回一个字符串。算术是不可靠的,我甚至在某些运行中得到了负面结果。应该使用microtime(true)将值作为浮点值。

我添加了另一个没有函数调用的测试,只是递增变量:

<?php

$param = 1;

$start = microtime(true);

for($i = 1; $i <= 1000000; $i++) {
    $param++;
}

$end = microtime(true);

echo "increment: " . ($end - $start) . "\n";

我的机器上的结果,Macbook 2.4GHz运行PHP 5.3.2。

  • 通过引用传递的函数调用: 2.14秒
  • 通过值传递的函数调用: 2.26秒
  • 没有函数调用,只是裸增量: 0.42秒

因此,通过引用传递似乎有5.3%的性能优势,但完全避免函数调用有81%的性能优势。

我想增加一个整数的例子是任意的,OP实际上是在询问通过引用传递的一般优势。但我只是提供这个例子来证明单独的函数调用会产生比传递参数的方法更多的开销。

因此,如果您正在尝试决定如何微观优化参数传递,那么您就是明智而且愚蠢。

还有其他原因可以避免引用。虽然它们可以简化几种算法,特别是当您操作两个或多个必须具有相同基础数据的数据结构时:

  • 他们使功能有副作用。一般来说,你应该避免使用带副作用的函数,因为它们会使程序更难以预测(如“好吧,这个值是如何实现的?是否有任何函数修改其参数?”)
  • 他们造成错误。如果将变量作为引用,则必须记住在为其赋值之前取消设置它,除非您想要更改引用集的基础值。在通过引用运行foreach循环然后重新使用循环变量之后,这种情况经常发生。

答案 1 :(得分:3)

这取决于功能目的是什么。如果其明确目的是修改输入,请使用引用。如果目的是根据输入计算一些数据,而来改变输入,请务必使用常规return

array_push

为例
int array_push(array &$array, mixed $var[, mixed $...])

此功能的明确目的是修改数组。你不太可能需要原始数组和它的副本,包括推送值。

array_push($array, 42); // most likely use case

// if you really need both versions, just do:
$old = $array;
array_push($array, 42);

如果array_push没有参考,您需要这样做:

// array_push($array, $var[, $...])
$array = array_push($array, 42); // quite a waste to do this every time

另一方面,像pow这样的纯计算函数不应该修改原始值:

number pow(number $base, number $exp)

您可能更有可能在要保持原始数字完整的上下文中使用此函数,并仅根据它计算结果。在这种情况下,如果pow修改了原始数字,那将是一件麻烦事。

$x = 123;
$y = pow($x, 42); // most likely use case

如果pow接受了引用,则需要执行此操作:

// pow(&$base, $exp)
$x = 123;
$y = $x; // nuisance
pow($y, 42);

答案 2 :(得分:2)

最佳做法是在表达式执行时不写函数。

$param++;

就是你所需要的一切。

答案 3 :(得分:2)

第二个版本:

function increment($param){
 return $param++;
}

$param = increment($param);

什么都不做。 increment()返回$ param。也许你的意思是++ $ param或$ param + 1;

我提到这不是迂腐,但是如果你比较时间,那么你正在比较相同的函数(PHP的优化器可能完全删除该函数)。

答案 4 :(得分:1)

根据定义,递增变量的值(至少在PHP中)会改变变量。它不需要一个值,将它增加1并返回它;相反,它改变了持有该值的变量。

所以你的第一个例子是更好的方法,因为它正在引用$param并且后期递增它的引用(PHP本身并不是指针)。

答案 5 :(得分:1)

我刚用以下代码进行了几次快速测试:

<?php

function increment(&$param){
 $param++;
}
$param = 1;

$start = microtime();

for($i = 1; $i <= 1000000; $i++) {
    increment($param);
}

$end = microtime();

echo $end - $start;

?>

此返回,始终在.42到.43之间,其中以下代码返回.55到.59 ​​

<?php

function increment($param){
 return $param++;
}
$param = 1;

$start = microtime();

for($i = 1; $i <= 1000000; $i++) {
    $param = increment($param);
}

$end = microtime();

echo $end - $start;

?>

所以我会说引用更快,但仅限于极端情况。

答案 6 :(得分:0)

我认为你的例子有点抽象。

使用指针没有问题但在大多数实际情况下你可能修改了一个对象而不是int,在这种情况下你不需要引用(至少在PHP5中)。

答案 7 :(得分:0)

我会说这完全取决于你在做什么。如果您尝试在大量数据上进行交互而不想在内存中添加额外的副本 - 请继续,按值传递(第二个示例)。如果你想保存内存,并直接在一个对象上进行交互 - 通过引用传递(你的第一个例子)