【问题标题】:PHP: Class Name Constant vs string performancePHP:类名常量与字符串性能
【发布时间】:2018-12-05 13:36:55
【问题描述】:

从 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 数组配置的框架,如果我在此配置解析方法中使用 ::class 的每个类名,而不是像字符串 '' 这样键入的全名-是否会对性能产生重要影响?

例如:

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

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

UPD:

我自己的测试

我编写简单的快速测试来进行基准测试

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 运行。

这是真的吗?

附:这不是如何测量 PHP 代码的重复,因为:

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

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

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

【问题讨论】:

  • 你为什么不做简单的测试?
  • 真正的项目配置文件中的数千行代码只是为了测试而更改并不简单

标签: php performance zend-framework2


【解决方案1】:

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

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

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

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

进一步说明基准测试

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

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

但归根结底,你真的不应该考虑是否要对它进行基准测试——这是一种语法上的精妙;它不影响性能。或者如果确实如此,那么效果太小了,不值得考虑。

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

【讨论】:

  • 如何正确地进行基准测试,有什么方法可以做到这一点吗?
  • 这个答案很棒!
猜你喜欢
  • 1970-01-01
  • 2019-01-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-15
  • 1970-01-01
  • 2011-02-06
  • 1970-01-01
相关资源
最近更新 更多