YiiBase :: createComponent optimization

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


			}


		}


Thanks. Will do. I don't like eval.

your welcome, prado has same problem too

optimized by Belarussian Yii team ))

Could you explain, what happens there? I feel like a newbie :)

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.

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?

Reflection is part of PHP ;)

http://us2.php.net/oop5.reflection

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.

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)

Removing eval() is good too for servers using PHP with Suhosin. Eval() is often blocked there, considered evil ;).

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.

how about:

$object = call_user_func_array(array($component, 'newInstance'), $args);

Good idea. Updated.

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

Thanks!