4

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

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

对比

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

$param = increment($param);
4

8 回答 8

10

首先,引用不是指针

我尝试了@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 循环然后重新使用循环变量后,这种情况经常发生。
于 2010-06-03T01:01:07.980 回答
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);
于 2010-06-03T01:21:31.637 回答
2

最好的做法是不要在表达式可以编写函数时编写函数。

$param++;

是你所需要的全部。

于 2010-06-03T00:39:18.320 回答
2

第二个版本:

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

$param = increment($param);

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

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

于 2010-06-03T01:57:28.843 回答
1

根据定义,增加变量的值(至少在 PHP 中)会改变变量。不取值,加1返回;相反,它会更改持有该值的变量。

因此,您的第一个示例将是更好的方法,因为它正在获取引用(PHP 本身并没有真正做指针)$param并对其进行后递增。

于 2010-06-03T00:34:09.053 回答
1

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

<?php

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

$start = microtime();

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

$end = microtime();

echo $end - $start;

?>

这返回,始终在 0.42 到 0.43 左右,而以下代码返回大约 0.55 到 0.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;

?>

所以我会说参考更快,但仅在极端情况下。

于 2010-06-03T00:35:41.497 回答
0

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

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

于 2010-06-03T00:38:58.543 回答
0

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

于 2010-06-03T00:40:38.350 回答