问题
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?
回答1:
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);
?
回答2:
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;
来源:https://stackoverflow.com/questions/24634165/php-performance-splat-operator-or-reflection