PHP:类名称常量vs字符串性能

时间:2015-09-17 12:28:42

标签: php performance zend-framework2

有一个功能从php 5.5开始,获取具有完整命名空间的类名,其中魔法内置class常量。例如

<?php
namespace Something\Obscenely\Long\Hard\To\Type;

class MyClass {
}

echo MyClass::class;
// Output: Something\Obscenely\Long\Hard\To\Type\MyClass
?>

以下是文档和RFC的链接 http://php.net/oop5.basic#language.oop5.basic.class.class https://wiki.php.net/rfc/class_name_scalars

问题是:

如果我使用Zend Framework 2,例如,已知为具有巨大php数组配置的框架,如果我在此configs解析方法中使用::class的每个类名,而不是仅使用类型为字符串{{ 1}} - 是否会产生有价值的性能影响?

例如:

''

VS

'controllers' => [
        'invokables' => [
            '\Controller\Monitor'  => 'Import\Controller\MonitorController',
...

UPD:

我自己的测试

我将简单的快速测试写入基准测试

'controllers' => [
            'invokables' => [
                '\Controller\Monitor'  => MonitorController::class,
    ...

结果与

类似
class MyClass
{
}

class MyClass1
{
}

class MyClass2
{
}

class MyClass3
{
}

/**
 * run many iteration loop for test percentage
 */
function testString()
{
    $results = [];

    for ($i = 0; $i < 150000; $i++) {

        $results[] = [
            'controllers' => [
                'invokables' => [
                    '\Controller\Monitor'  => 'Import\Controller\MonitorController',
                    '\Controller\Monitor2' => 'Import\Controller\MonitorController2',
                    '\Controller\Monitor3' => 'Import\Controller\MonitorController3',
                    '\Controller\Monitor4' => 'Import\Controller\MonitorController4',
                ]
            ]
        ];
    }

    return $results;
}

function testClass()
{
    $results = [];

    for ($i = 0; $i < 150000; $i++) {

        $results[] = [
            'controllers' => [
                'invokables' => [
                    '\Controller\Monitor'  => MyClass::class,
                    '\Controller\Monitor2' => MyClass1::class,
                    '\Controller\Monitor3' => MyClass2::class,
                    '\Controller\Monitor4' => MyClass3::class,
                ]
            ]
        ];
    }

    return $results;
}

$token = Benchmark::start('testString');

testString();

Benchmark::end($token);

$token = Benchmark::start('testClass');

testClass();

Benchmark::end($token);

exit();

我们可以看到testString 215335.203125 Kbytes Time: 0.2604 Seconds testClass 215337.1640625 Kbytes Time: 0.2508 Seconds 更快。运行最新的php5.6。

真的可以吗?

P.S。它与如何衡量PHP代码并不重复,因为:

  1. 我没有在搜索引擎中询问的信息。
  2. 我不知道如何衡量这个问题背景下的表现, 因为对于这种情况,运行基准测试不够和困难。

  3. 在实际项目中更改数千行代码并不简单 配置文件。

  4. 我想要更详细的答案 - 不仅是数字,还有 还为什么?

1 个答案:

答案 0 :(得分:20)

如果代码中有::class,那么实际发生的是PHP获取您指定的类的名称并生成完全限定的命名空间类名作为字符串。所以是的,这确实意味着你让计算机做的工作比你刚提供字符串要多。

但是,它在编译时执行 。这意味着它只会执行一次,并且它发生在程序运行时的范围之外。因此,您的Benchmark性能计时器不会将其考虑在内 - 实际上当您的代码运行时,它只会看到一个字符串,这意味着您实际进行基准测试的是程序执行几乎完全相同的事情。两种情况。两者之间的时间差异是一个人工制品,可以忽略不计。

关于它在编译时完成的另一个重点是,如果你启用了OpCache,那么它只需要在第一次运行它时将字符串转换一次,这意味着它们之间的区别更小两个。

出于性能原因,未将::class语法添加到语言中;之所以添加,是因为它有助于提高代码质量,可读性和可维护性。坦率地说,这些因素几乎总是比微观优化的表现更重要。

进一步澄清bencharking

由于它是在编译时完成的,因此无法从PHP程序内部获得准确的基准。

如果你真的想要对它进行基准测试,你最好的选择就是用一个定时器编写一个shell脚本并从那里调用程序。您需要为每个变体都有一个单独的PHP程序。但即便如此,您获得的任何基准测试结果都会有些人为,并且不可能以任何有意义的方式发挥作用。根据您是在程序的单个实例中运行多个循环还是在shell脚本中使用循环,您将获得不同的结果。如果启用了OpCache,您也会得到不同的结果。

但最终,你真的不应该考虑是否对此进行基准测试 - 这是一种语法准确;它不会影响性能。或者如果确实如此,效果非常小,不值得考虑。

良好性能调优的秘诀在于找到代码中最大的瓶颈,并首先处理它们。不是最小的。