Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP: Class Name Constant vs string performance

There is a feature started from php 5.5 to get class name with full namespace with magic built in class constant. For example

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

class MyClass {
}

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

Here is links for documentation and RFC http://php.net/oop5.basic#language.oop5.basic.class.class https://wiki.php.net/rfc/class_name_scalars

The question is:

If I use Zend Framework 2, for example, which known as framework with huge php arrays configs, if I use for every class name in this configs resolution method with ::class against just full names typed like strings ''- is there a valuable performance impact?

For example:

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

vs

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

UPD:

My own tests

I write simple fast test to benchmark

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();

And results is similar to

testString
215335.203125 Kbytes
Time: 0.2604 Seconds
testClass
215337.1640625 Kbytes
Time: 0.2508 Seconds

We can see that ::class is faster. Run with latest php5.6.

Can it be true ?

P.S. It's not a duplicate of How to measure PHP code because:

  1. There is no information what I'm asking about in search engines.
  2. I don't know how to measure performance in this question context, because for this case running benchmark not enough and difficult.

  3. It's not simple to change thousands lines of code in real project config files.

  4. I want more detailed answer - not only numbers, but also why?
like image 670
Oleg Abrazhaev Avatar asked Sep 17 '15 12:09

Oleg Abrazhaev


1 Answers

When you have ::class in your code, what actually happens is that PHP takes the name of the class you've specified and generates the fully-qualified namespaced classname as a string. So yes, this does indeed mean that you're getting the computer to do more work than if you'd just supplied a string.

However, it does this at compile time. This means that it will only ever do it once, and it happens outside of the bounds of your program runtime. Therefore your Benchmark performance timer won't take it into account -- in fact when your code runs, it just sees a string, which means that what you're actually benchmarking is the program doing virtually exactly the same thing in both scenarios. Any difference in timing between the two is an artifact and can be ignored.

The other important point about it being done at compile time is that if you have OpCache enabled then it will only ever have to convert the string once, the first time you run it, which means that there's even less of a difference between the two.

The ::class syntax wasn't added to the language for performance reasons; it was added because it helps with code quality, readability and maintainability. And frankly, those factors are almost always far more important than micro-optimised performance.

Further clarification on bencharking

Since it's done at compile time, you can't get an accurate benchmark for it from inside of the PHP program.

If you really want to benchmark it, your best option would be to write a shell script with a timer and call the program from there. You'll need to have a separate PHP program for each variation. But even then, any benchmark results you get will be somewhat artificial and unlikely to be useful in any meaningful way. You'll get different results depending on whether you run multiple loops in a single instance of the program or have the loop in the shell script. You'll also get different results if you have OpCache enabled.

But ultimately, you really shouldn't even be thinking about whether to benchmark this -- it's a syntax nicety; it doesn't affect performance. Or if it does, the effect is so tiny that it's not worth thinking about.

The secret of good performance tuning is to find the biggest bottlenecks in your code, and deal with them first. Not the smallest.

like image 136
Simba Avatar answered Oct 23 '22 03:10

Simba