PHP: Class 名称常量与字符串性能

PHP: Class Name Constant vs string performance

从 php 5.5 开始有一项功能可以获取 class 具有完整命名空间的名称,魔法内置 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 数组配置的框架,如果我在此配置解析方法中使用每个 class 名称 ::class 而不是像字符串一样键入全名 ''- 对性能有重要影响吗?

例如:

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

'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

我们可以看到 ::class 更快。 运行 最新 php5.6.

这是真的吗?

P.S。它不是 How to measure PHP 代码的副本,因为:

  1. 搜索引擎中没有我要查询的信息。
  2. 我不知道如何衡量这个问题上下文中的性能, 因为对于这种情况 运行 基准测试还不够而且困难。

  3. 真实项目改几千行代码不简单 配置文件。

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

当你的代码中有 ::class 时,实际发生的是 PHP 使用你指定的 class 的名称并生成完全限定的命名空间 class名称作为字符串。所以是的,这确实意味着你让计算机做的工作比你只提供一个字符串要多。

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

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

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

关于基准测试的进一步说明

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

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

但最终,您真的不应该考虑是否对此进行基准测试——这是一种语法上的好处;它不会影响性能。或者即使有,影响也很小,不值得考虑。

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