PHP 5 反射 API 性能

2022-08-30 09:28:40

我目前正在考虑在我自己的MVC Web框架中使用Reflection类(主要是ReflectralClass和ReflectionMethod),因为我需要自动实例化控制器类并调用它们的方法,而无需任何必需的配置(“约定超过配置”方法)。

我担心性能,即使我认为数据库请求可能比实际的PHP代码更大的瓶颈。

所以,我想知道从性能的角度来看,是否有人对PHP 5 Reflection有任何好或坏的体验。

此外,我很想知道是否有任何一个流行的PHP框架(CI,Cake,Symfony等)实际上使用Reflectle。


答案 1

我对这3个选项进行了基准测试(另一个基准测试不是拆分CPU周期,而是4y年前):

class foo {
    public static function bar() {
        return __METHOD__;
    }
}

function directCall() {
    return foo::bar($_SERVER['REQUEST_TIME']);
}

function variableCall() {
    return call_user_func(array('foo', 'bar'), $_SERVER['REQUEST_TIME']);
}

function reflectedCall() {
    return (new ReflectionMethod('foo', 'bar'))->invoke(null, $_SERVER['REQUEST_TIME']);
}

1,000,000 次迭代所需的绝对时间:

print_r(Benchmark(array('directCall', 'variableCall', 'reflectCall'), 1000000));

Array
(
    [directCall] => 4.13348770
    [variableCall] => 6.82747173
    [reflectedCall] => 8.67534351
)

和相对时间,也有1,000,000次迭代(单独运行):

ph()->Dump(Benchmark(array('directCall', 'variableCall', 'reflectCall'), 1000000, true));

Array
(
    [directCall] => 1.00000000
    [variableCall] => 1.67164707
    [reflectedCall] => 2.13174915
)

似乎在5.4.7中反射性能大大提高(从~500%下降到~213%)

如果有人想要重新运行此基准测试,以下是我使用的函数:Benchmark()

function Benchmark($callbacks, $iterations = 100, $relative = false)
{
    set_time_limit(0);

    if (count($callbacks = array_filter((array) $callbacks, 'is_callable')) > 0)
    {
        $result = array_fill_keys($callbacks, 0);
        $arguments = array_slice(func_get_args(), 3);

        for ($i = 0; $i < $iterations; ++$i)
        {
            foreach ($result as $key => $value)
            {
                $value = microtime(true);
                call_user_func_array($key, $arguments);
                $result[$key] += microtime(true) - $value;
            }
        }

        asort($result, SORT_NUMERIC);

        foreach (array_reverse($result) as $key => $value)
        {
            if ($relative === true)
            {
                $value /= reset($result);
            }

            $result[$key] = number_format($value, 8, '.', '');
        }

        return $result;
    }

    return false;
}

答案 2

不要担心。安装Xdebug,并确保瓶颈在哪里。

使用反射是有代价的,但这是否重要取决于你在做什么。如果您使用反射实现控制器/请求调度程序,则每个请求仅使用一次。绝对可以忽略不计。

如果您使用反射实现ORM层,将其用于每个对象甚至对属性的每次访问,并创建数百或数千个对象,那么它可能会很昂贵。


推荐