素材牛VIP会员
PHP 的 call_user_func_array 方法是否效率很低?
 许***焱  分类:PHP代码  人气:1317  回帖:7  发布于6年前 收藏

Laravel 5.1Facade 类 的 __callStatic 方法代码如下:

public static function __callStatic($method, $args)
{
    $instance = static::getFacadeRoot();

    if (! $instance) {
        throw new RuntimeException('A facade root has not been set.');
    }

    switch (count($args)) {
        case 0:
            return $instance->$method();

        case 1:
            return $instance->$method($args[0]);

        case 2:
            return $instance->$method($args[0], $args[1]);

        case 3:
            return $instance->$method($args[0], $args[1], $args[2]);

        case 4:
            return $instance->$method($args[0], $args[1], $args[2], $args[3]);

        default:
            return call_user_func_array([$instance, $method], $args);
    }
}

为什么不直接写成:

public static function __callStatic($method, $args)
{
    $instance = static::getFacadeRoot();

    if (! $instance) {
        throw new RuntimeException('A facade root has not been set.');
    }

    return call_user_func_array([$instance, $method], $args);
}
 标签:phplaravel

讨论这个帖子(7)垃圾回帖将一律封号处理……

Lv6 码匠
雾***n 页面重构设计 6年前#1

答:call_user_func_array 效率偏低。

基准测试如下

对比范围

  • 直接调用

  • 变量函数调用

  • call_user_func 调用

  • call_user_func_array 调用

测试结果


我们可以看到,call_user_func_array 所用时间为:1.1608240604401s

测试过程

测试代码如下:

<?php
error_reporting(E_ALL | E_STRICT);
define('ITERATIONS', 2000000);

class Bench
{
    private $bench_name;
    private $start_time;
    private $end_time;

    public function start($name)
    {
        $this->bench_name = $name;
        $this->start_time = microtime(true);
    }

    public function end()
    {
        $this->end_time = microtime(true);
        echo "Call style: " . $this->bench_name . '; ' . ($this->end_time - $this->start_time) . " seconds". PHP_EOL;
    }
}

class Test
{
    public function test($a, $b, $c)
    {
        return;
    }
}


$bench = new Bench();
$test = new Test();
$arg = [1, 2, 3];
$func_name = 'test';

$bench->start('normal');
for ($i=0; $i < ITERATIONS; ++$i) {
    $test->test($arg[0], $arg[1], $arg[2]);
}
$bench->end();

$bench->start('var_function');
for ($i=0; $i < ITERATIONS; ++$i) {
    $test->$func_name($arg[0], $arg[1], $arg[2]);
}
$bench->end();

$bench->start('call_user_func');
for ($i=0; $i < ITERATIONS; ++$i) {
    call_user_func([$test, $func_name], $arg[0], $arg[1], $arg[2]);
}
$bench->end();

$bench->start('call_user_func_array');
for ($i=0; $i < ITERATIONS; ++$i) {
    call_user_func_array([$test, $func_name], $arg);
}
$bench->end();
Lv5 码农
lu***ha 软件测试工程师 6年前#2

我刚刚创建了一个laravel的项目

"laravel/framework": "5.5.*"

然后看了源码:

/**
 * Handle dynamic, static calls to the object.
 *
 * @param  string  $method
 * @param  array   $args
 * @return mixed
 *
 * @throws \RuntimeException
 */
public static function __callStatic($method, $args)
{
    $instance = static::getFacadeRoot();

    if (! $instance) {
        throw new RuntimeException('A facade root has not been set.');
    }

    return $instance->$method(...$args);
}
Lv1 新人
多***悟 学生 6年前#3

这问题我也纳闷. mark, 看会不会遇到能解答这个问题的人.

Lv6 码匠
谎***y 技术总监 6年前#4

光看题主的问题, php 中的 call_user_func_array() 并不慢, 相反这个比普通的函数执行更快, 因为这个在 php7 添加为语言结构(其他语言结构, 比如 echo), 这个信息可以从鸟哥的博客获取到.

另外 laravel 中 facade 中多这样一层封装, 其实是使用 __callStatic() 函数实现, 这个稍微会有一点性能损失.

Lv5 码农
Co***ht 软件测试工程师 6年前#5

三个...不定参数的写法是php 5.6版本才有的新特性,我猜可能框架5.1版本的时候还没支持php新特性的吧

Lv1 新人
ze***an UI设计师 6年前#6

题主是不是看错了或者看的是修改过的源码,原始laravel中并没有发现存在这些代码,能否标出具体的laravel版本和文件路径

我看到的laravel的 Facade 类中代码是这样的

/**
     * Handle dynamic, static calls to the object.
     *
     * @param  string  $method
     * @param  array   $args
     * @return mixed
     *
     * @throws \RuntimeException
     */
    public static function __callStatic($method, $args)
    {
        $instance = static::getFacadeRoot();

        if (! $instance) {
            throw new RuntimeException('A facade root has not been set.');
        }

        return $instance->$method(...$args);
    }
Lv5 码农
zh***23 PHP开发工程师 6年前#7

额 题主是什么版本的啊? 感觉跟楼上就几个同学看到的一样啊

 文明上网,理性发言!   😉 阿里云幸运券,戳我领取