vamp
(Vamphouse)
March 5, 2009, 12:46pm
1
if(($n=func_num_args())>1)
{
$args=func_get_args();
for($s='$args[1]',$i=2;$i<$n;++$i)
$s.=",$args[$i]";
eval("$object=new $type($s);");
}
need in replacing to
if(($n = func_num_args())>1)
{
$args=func_get_args();
if( 2 === $n ){
$object = new $type($args[1]);
}
else{
unset($args[0]);
$component = new ReflectionClass($type);
$object = $component->newInstanceArgs($args);
}
}
qiang
(Qiang Xue)
March 5, 2009, 12:54pm
2
Thanks. Will do. I don't like eval.
vamp
(Vamphouse)
March 5, 2009, 1:00pm
3
your welcome, prado has same problem too
optimized by Belarussian Yii team ))
KJedi
(Konstantin Mirin)
March 5, 2009, 2:02pm
4
Could you explain, what happens there? I feel like a newbie
qiang
(Qiang Xue)
March 5, 2009, 3:48pm
5
We are trying to replace eval() call in order to create an object that needs constructor parameters. eval() is not good because if there's some constructor error, the call stack may not look nice (and there may be other problems). It may also be inefficient compared with using 'new' operator.
KJedi
(Konstantin Mirin)
March 5, 2009, 3:56pm
6
Yes, I understood that, but what is ReflectionClass and how is it used to create the component when there is several parameters there? newInstanceArgs method does this magic? Is there any articles on the web to read about this? Or at least how to ask google about it?
mikl
(Mike)
March 5, 2009, 3:59pm
7
KJedi
(Konstantin Mirin)
March 5, 2009, 5:18pm
8
Yes, I knew that, just wanted more info on it. After googling I understood, what’s done there and found a couple of interesting things. For example, using reflection for building simple web service
Thanks for clarifying this.
vamp
(Vamphouse)
March 11, 2009, 8:49am
9
Qiang, I checked latest release, but didn't found any code optimization, then I create next test:
public function createComponentReflect($type){
if(($n=func_num_args())>1)
{
$args=func_get_args();
if($n===2)
$object=new $type($args[1]);
elseif($n===3)
$object=new $type($args[1],$args[2]);
else
{
unset($args[0]);
$component=new ReflectionClass($type);
$object=$component->newInstanceArgs($args);
}
}
return $object;
}
public function createComponentEval($type){
if(($n=func_num_args())>1)
{
$args=func_get_args();
if($n===2)
$object=new $type($args[1]);
elseif($n===3)
$object=new $type($args[1],$args[2]);
else
{
for($s='$args[1]',$i=2;$i<$n;++$i)
$s.=",$args[$i]";
eval("$object=new $type($s);");
}
}
return $object;
}
public function actionTest()
{
$i = 1e+5;
$args = array('SiteController', 1, 2, 3);
$mRef = null;
$mEva = null;
while($i--){
$m1 = microtime(true);
call_user_func_array(array($this, 'createComponentReflect'), $args);
$m2 = microtime(true)-$m1;
$mRef = ($mRef==null)? $m2 : ($mRef+$m2)/2;
$m1 = microtime(true);
call_user_func_array(array($this, 'createComponentEval'), $args);
$m2 = microtime(true)-$m1;
$mEva = ($mEva==null)? $m2 : ($mEva+$m2)/2;
}
echo $mRef, "n", $mEva;
exit;
}
Result is:
3.4557783888792E-5
5.754639907143E-5
3.45 (Reflection) vs. 5.75 (eval)
Maxximus
(Maxximus007)
March 11, 2009, 10:15am
10
Removing eval() is good too for servers using PHP with Suhosin. Eval() is often blocked there, considered evil .
qiang
(Qiang Xue)
March 11, 2009, 11:27am
11
The optimization is done when there are one or two constructor parameters.
I didn't use ReflectionClass because newInstanceArgs() is only available after PHP 5.1.4 or something. It's not very common to use constructor with more than 2 parameters.
vamp
(Vamphouse)
March 11, 2009, 11:41am
12
how about:
$object = call_user_func_array(array($component, 'newInstance'), $args);
vamp
(Vamphouse)
March 13, 2009, 10:12am
14
In last revision was a mistake (component configuration was skipped):
--- .../framework/YiiBase.php (revision 831)
+++ .../framework/YiiBase.php (working copy)
@@ -172,7 +172,7 @@
$class=new ReflectionClass($type);
// Note: ReflectionClass::newInstanceArgs() is available for PHP 5.1.3+
// return $class->newInstanceArgs($args);
- return call_user_func_array(array($class,'newInstance'),$args);
+ $object=call_user_func_array(array($class,'newInstance'),$args);
}
}
else