PHP函数调用的重要性有多大?

Jos*_*son 10 php optimization php-5.2

我对PHP比较陌生,慢慢学习特定于语言的特性.有一件事我得到了很大的好处,那就是我(所以我被告知)使用了太多的函数调用,并且我被要求做一些事情来解决它们.这是两个例子:

// Change this:
} catch (Exception $e) {
  print "It seems that error " . $e->getCode() . " occured";
  log("Error: " . $e->getCode());
}

// To this:
} catch (Exception $e) {
  $code = $e->getCode();
  print "It seems that error " . $code . " occured";
  log("Error: " . $code);
}
Run Code Online (Sandbox Code Playgroud)

第二个例子

// Change this:
$customer->setProducts($products);

// To this:
if (!empty($products)) {
  $customer->setProducts($products);
}
Run Code Online (Sandbox Code Playgroud)

在第一个例子中,我发现$e->getCode()$code广告分配一个轻微的认知开销; "什么是'$ code'?啊,这是异常的代码." 而第二个例子增加了圈复杂度.在这两个例子中,我发现优化是以可读性和可维护性为代价的.

性能提升是值得的,还是微观优化?

我应该注意到,我们现在仍然坚持使用PHP 5.2.

我做了一些非常粗略的基准测试,发现函数调用性能命中率在10%到70%之间,具体取决于我的工作台测试的性质.我承认这很重要.但在该catch块被击中之前,有一个数据库和HTTP端点的调用.在$products设置之前,$customer有一个复杂的排序发生在$products数组.在一天结束时,这种优化是否证明了使代码更难以阅读和维护的成本?或者,虽然这些例子都是简化,但是有没有人发现第二个例子比第一个例子容易或更容易阅读(我是一个维纳)?

任何人都可以引用任何好的文章或研究吗?

编辑:

一个示例基准测试:

<?php
class Foo {
        private $list;
        public function setList($list) {
                $this->list = $list;
        }
}

$foo1 = new Foo();

for($i = 0; $i < 1000000; $i++) {
        $a = array();
        if (!empty($a))
                $foo1->setList($a);
}
?>
Run Code Online (Sandbox Code Playgroud)

使用该time命令运行该文件.在一台特定的机器上,经过几次运行后平均需要0.60秒.评论if (!empty($a))它导致平均运行3.00秒的原因.

澄清:这些都是例子.第一个示例演示了可怕的异常处理和可能的DRY违规,但代价是一个简单的,非特定于域的示例.

use*_*198 6

PHP函数调用开销恰好是15.5355%.

:)只是搅拌锅.

说真的,这里有几个很棒的链接:

是否有可能在PHP应用程序中有太多的功能?

函数与重复代码

这些链接上的代码可维护性与速度讨论解决了OP所暗示的(可能更重要的)问题,但只是为了添加一些可能相关的小数据,并希望将来遇到这个线程的人有用,这里是在2011 Macbook Pro上运行以下代码的结果(驱动器空间非常小,运行的程序太多).

如其他地方所述,在决定是否调用函数或将代码"内联"时,一个重要的考虑因素是在某个代码块中调用函数的次数.函数调用的次数越多,在线工作就越值得考虑.

结果(以秒为单位的时间)

呼叫功能方法| 在线方法| 差异| 百分比不同

1,000次迭代(4次运行)

0.0039088726043701 | 0.0031478404998779 | 0.00076103210449219 | 19.4694

0.0038208961486816 | 0.0025999546051025 | 0.0012209415435791 | 31.9543

0.0030159950256348 | 0.0029480457305908 | 6.7949295043945E-5 | 2.2530

0.0031449794769287 | 0.0031390190124512 | 5.9604644775391E-6 | 0.1895

1,000,000次迭代(4次运行)

3.1843111515045 | 2.6896121501923 | 0.49469900131226 | 15.5355

3.131945848465 | 2.7114839553833 | 0.42046189308167 | 13.4249

3.0256152153015 | 2.7648048400879 | 0.26081037521362 | 8.6201

3.1251409053802 | 2.7397727966309 | 0.38536810874939 | 12.3312

function postgres_friendly_number($dirtyString) {

    $cleanString = str_ireplace("(", "-", $dirtyString);
    $badChars = array("$", ",", ")");
    $cleanString = str_ireplace($badChars, "", $cleanString);

    return $cleanString;

}


//main
$badNumberString = '-$590,832.61';

$iterations = 1000000;

$startTime = microtime(true);
for ($i = 1; $i <= $iterations; $i++) {
    $goodNumberString = postgres_friendly_number($badNumberString);
}
$endTime = microtime(true);
$firstTime = ($endTime - $startTime); 

$startTime = microtime(true);
for ($i = 1; $i <= $iterations; $i++) {
    $goodNumberString = str_ireplace("(", "-", $badNumberString);
    $badChars = array("$", ",", ")");
    $goodNumberString = str_ireplace($badChars, "", $goodNumberString);
}
$endTime = microtime(true); 
$secondTime = ($endTime - $startTime); 

$timeDifference = $firstTime - $secondTime;
$percentDifference = (( $timeDifference / $firstTime ) * 100);
Run Code Online (Sandbox Code Playgroud)

  • 这完全没用,因为它甚至没有提到使用的是哪个版本的 PHP。 (2认同)

小智 6

目前还没有人讨论过服务器硬件与函数调用开销的关系.

调用函数时,所有CPU的寄存器都包含与当前执行点相关的数据.所有CPU的寄存器必须保存到内存中(通常是进程的堆栈),或者没有希望永远返回到该执行点并继续执行.从函数返回时,必须从内存(通常是进程'堆栈)恢复所有CPU的寄存器.

因此,可以看到一串嵌套函数调用如何为进程增加开销.CPU的寄存器必须一遍又一遍地保存在堆栈中,并反复恢复以从函数中恢复.

这实际上是函数调用开销的来源.如果传递了函数参数,那么在调用函数之前必须重复这些参数.因此,将大型数组作为函数参数传递是一种糟糕的设计.

在使用getter/setter的开销上已经对面向对象的PHP进行了研究.删除所有getter/setter会将执行时间缩短约50%.而这仅仅是由于函数调用开销.


Esa*_*ija 5

规范的 PHP 实现非常慢,因为它易于实现,而且 PHP 所针对的应用程序不需要像快速函数调用那样的原始性能。

您可能需要考虑其他PHP 实现

如果您正在编写应该用 PHP 编写的应用程序(通过网络将数据从 DB 转储到浏览器),那么函数调用开销并不大。当然不要特意去复制代码,因为你担心使用一个函数会带来太多的开销。