Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP: Performance: splat operator or reflection

Tags:

php

php-5.6

In an app that I'm creating, I need to pass an unknown number of parameters to an unknown constructor of a class. The class (+ namespace) is a string, that is in $class. The parameters are in an array.

This application will be deployed over a couple of months, so we thought we could develop it already in PHP 5.6. So I thought that the solution of this would be:

$instance = new $class(...$args);

This is working...

But my collegues don't want to accept this, because the CI server does not understand this line of code. Their solution would rather be:

$reflect = new \ReflectionClass($class);
$instance = $reflect->newInstanceArgs($args)

Now: both are working fine, so that's not the problem. But my thought is that Reflection is slower then using other ways (like the PHP 5.6 splat operator).

Also the question: is reflection a good way, of should I use the splat operator from the moment the CI server does understand that line?

like image 787
Blaatpraat Avatar asked Dec 08 '22 07:12

Blaatpraat


2 Answers

Definitely go for the splat operator, why? It's much faster than the reflection approach (I'm using it and the implementation seems to be very good). Also reflection breaks just about anything that has to do with design, it allows you to break encapsulation for instance.

PS: Isn't it $instance = new $class(...$args);?

like image 60
Fleshgrinder Avatar answered Dec 11 '22 12:12

Fleshgrinder


Today I've found the time to benchmark it.
And it's like I've expected (and Fleshgrinder said): the splat operator is faster.

Benchmark times:
Reflection: 11.686084032059s
Splat: 6.8125338554382s

Almost the half of time... That's serious...

Benchmark (via http://codepad.org/jqOQkaZR):

<?php

require "autoload.php";

function convertStdToCollectionReflection(array $stds, $entity, $initVars)
{
    $records = array();
    $class = $entity . '\\Entity';
    foreach ($stds as $record) {
        $args = array();
        foreach ($initVars as $var) {
            $args[] = $record->$var;
        }
        $reflect = new \ReflectionClass($class);
        $records[] = $reflect->newInstanceArgs($args);
    }

    return $records;
}

function convertStdToCollectionSplat(array $stds, $entity, $initVars)
{
    $records = array();
    $class = $entity . '\\Entity';
    foreach ($stds as $record) {
        $args = array();
        foreach ($initVars as $var) {
            $args[] = $record->$var;
        }
        $records[] = new $class(...$args);
    }

    return $records;
}

$dummyObject = array();
for ($i = 0; $i < 10; $i++) {
    $dummyclass = new \stdClass();
    $dummyclass->id = $i;
    $dummyclass->description = 'Just a number... ' . $i;
    $dummyObject[] = $dummyclass;
}

print 'Start Reflection test' . PHP_EOL;
$reflectionStart = microtime(true);

for($i = 0; $i < 1000000; $i++) {
    convertStdToCollectionReflection(
        $dummyObject,
        'Xcs\Core\Record',
        array(
            'id',
            'description'
        )
    );
}

$reflectionEnd = microtime(true);

print 'Start Splat test' . PHP_EOL;
$splatStart = microtime(true);

for($i = 0; $i < 1000000; $i++) {
    convertStdToCollectionSplat(
        $dummyObject,
        'Xcs\Core\Record',
        array(
            'id',
            'description'
        )
    );
}

$splatEnd = microtime(true);

print PHP_EOL . 'OUTPUT:' . PHP_EOL;
print 'Reflection: ' . ($reflectionEnd - $reflectionStart) . 's' . PHP_EOL;
print 'Splat: ' . ($splatEnd - $splatStart) . 's' . PHP_EOL;
like image 38
Blaatpraat Avatar answered Dec 11 '22 12:12

Blaatpraat