This article mainly introduces how to understand the role of reflection in the DI container source code of the YII2 framework, has a certain reference value, now share to everyone, the need for friends can refer to
Introduction to Reflection
Referring to the official profile, PHP 5 has a complete reflection API that adds the ability to reverse engineer classes, interfaces, functions, methods, and extensions. In addition, the reflection API provides a way to remove document comments from functions, classes, and methods.
Examples in the YII2 framework
For the YII2 framework, should all know di container, for DI container source code here is also mainly about the container class, first look at how to use di in peacetime, with the YII2 Framework annotated sample code to display;
Container Invocation Example
namespace App\models;use yii\base\baseobject;use Yii\db\connection;use yii\di\container;interface userfinderinterface{function Finduser ();} Class Userfinder extends Baseobject implements userfinderinterface{public $db; Public function __construct (Connection $db, $config = []) {$this->db = $db; Parent::__construct ($config); Public Function Finduser () {}} class Userlister extends Baseobject {public $finder; Public function __construct (userfinderinterface $finder, $config = []) {$this->finder = $finder; Parent::__construct ($config); }} $container = new container; $container->set (' yii\db\connection ', [' dsn ' = ' ... ',]); $container->set (' App\models\userfinderinterface ', [' class ' = ' App\models\userfinder ',]); $container->set (' Userlister ', ' app\models\userlister '); $lister = $container->get (' Userlister '); The above actions are equivalent to the following implementations $db = new \yii\db\connection ([' DSN ' = ' ... ']); $finder = new Userfinder ($DB); $lister = new Userlister ($finder);
The example code above simply instantiates the container class, then calls the set method to inject the other object, and finally gets the Lister object that relies on the creation of the other object, since only the set method and the Get method are called, the container code begins with the set of the most calls.
Set method
Public function set ($class, $definition = [], array $params = []) { $this->_definitions[$class] = $this->normali Zedefinition ($class, $definition); $this->_params[$class] = $params; unset ($this->_singletons[$class]); return $this;}
The above code is relatively concise, called the Normalizedefinition method of the class, this one will say, first explain the meaning of the three attributes that appear in the method
_definitions array, saving dependency definitions
_params array, saving arguments to constructors
_singletons, saving a single case
Look at the Normalizedefinition method, the main function of this method is to standardize the class definition
protected function normalizedefinition ($class, $definition) {if (Empty ($ definition)) {//Empty return [' class ' = $class]; } elseif (Is_string ($definition)) {//String return [' class ' = = $definition]; } elseif (Is_callable ($definition, true) | | is_object ($definition)) {//check whether a callable function or object return $definition; } elseif (Is_array ($definition)) {//detects if the array if (!isset ($definition [' class '])) {if (Strpos ($CL , ' \ \ ')!== {$definition [' class '] = $class; } else {throw new Invalidconfigexception (' A class definition requires a "class" member. '); }} return $definition; } throw new Invalidconfigexception ("Unsupported definition type for \" $class \ ":". GetType ($definition));}
Some of the above code has made some comments, it is not difficult to find that the final need to return the definition variable needs an array format, or can call functions and objects, notice back to the beginning of the call sample code, the definition variable has an array format without the class key,
The array is formatted with the class key, with the string type. In the end, the Set method call is complete, from the source of the analysis basically do not see the reflection of the shadow, that is, some of the input parameter format compatible processing and then write class properties, and then look at the sample code in the Get method.
Get method
Public function Get ($class, $params = [], $config = []) {if (Isset ($this->_singletons[$class])) {//return directly to the singleton return $this->_singletons[$class]; } elseif (!isset ($this->_definitions[$class])) {//Call Bulid return $this->build ($class, $params, $conf IG); } $definition = $this->_definitions[$class]; if (Is_callable ($definition, True)) {//callable function Condition $params = $this->resolvedependencies ($this->mergepara MS ($class, $params)); $object = Call_user_func ($definition, $this, $params, $config); } elseif (Is_array ($definition)) {//array $concrete = $definition [' class ']; unset ($definition [' class ']); $config = Array_merge ($definition, $config); $params = $this->mergeparams ($class, $params); if ($concrete = = = $class) {$object = $this->build ($class, $params, $config); } else {$object = $this->get ($concrete, $params, $config); }} ELseif (Is_object ($definition)) {//objects are saved directly to the Singleton property set to return $this->_singletons[$class] = $definition; } else {throw new Invalidconfigexception (' Unexpected object definition type: '. GetType ($definition)); } if (Array_key_exists ($class, $this->_singletons)) {//Singleton $this->_singletons[$class] = $ob ject; } return $object;}
The above code, briefly divided, please a little to browse, the following will continue to explain, the first description of the property _definitions collection does not exist in the case, that is, call build, this one will explain, and then see if there is a relevant class key situation, the following will do several cases of processing,
Callable function, call resolvedependencies method, and then call_user_func call function
In the case of arrays, get the value compared to class, equal to the case to call the build method, do not want to call the Get method to use the value
The object is stored directly into the _singletons property collection and returned directly to the object, which is not a repeat
The following is a brief analysis of several methods of the above call, Bulid and Resolvedependencies method
Invocation logic for the Bulid method
First look at the build method call source
The protected function build ($class, $params, $config) {//Declaration variable stores the array returned by the Getdependencies method, which is the list ($reflection, $dependencie s) = $this->getdependencies ($class); The data of the params array is mergy and overwritten into the variable $dependencies foreach ($params as $index = = $param) {$dependencies [$index] = $para M }//Call the Resolvedependencies method $dependencies = $this->resolvedependencies ($dependencies, $reflection); Call the Reflection class method to detect if the class can instantiate if (! $reflection->isinstantiable ()) {throw new notinstantiableexception ($reflection-> ; name); if (empty ($config)) {//Creates a new instance of a class, the variable $dependencies is passed as a parameter to the constructor of the class. Return $reflection->newinstanceargs ($dependencies); } $config = $this->resolvedependencies ($config); If the variable $dependencies is empty and class is the implementation of the Yii\base\configurable interface if (!empty ($dependencies) && $reflection Implementsinterface (' yii\base\configurable ')) {//set $config as the last parameter (existing one'll be Overwrit Ten) $dependencies[Count ($dependencies)-1] = $config; Return $reflection->newinstanceargs ($dependencies); }//Create object, inject parameter $object = $reflection->newinstanceargs ($dependencies); object property Assignment foreach ($config as $name = = $value) {$object $name = $value; } return $object;}
Read the above source, also basic understanding of this method is to return the instantiation of the object, and called some of the reflection of the interface functions, here can basically know some of the role of reflection, the first is to detect the legality of the class, for example, whether the detection is an interface implementation, whether it can be instantiated,
Another is creation, which can be seen by creating an instance of a class based on reflection and injecting parameters that are dependent on the constructor. The following is an understanding of the method calls the two dependent methods, respectively, the beginning of the variable declaration getdependencies and Resolvedependencies
Processing variables.
Getdependencies Method Invocation
protected function Getdependencies ($class) {//detects if the reflection already exists if (Isset ($this->_reflections[$class])) {return [$this->_reflections[$class], $this->_dependencies[$class]]; } $dependencies = []; $reflection = new Reflectionclass ($class); The information of the corresponding class of reflection $constructor = $reflection->getconstructor (); Gets the constructor of the class if ($constructor!== null) {//If the constructor is not empty, gets the arguments in the constructor loop processing foreach ($constructor->getparamet ERS () as $param) {if (Version_compare (php_version, ' 5.6.0 ', ' >= ') && $param->isvariadic ()) { Detects if the PHP version and the construction parameters are detected as variable parameters break; } elseif ($param->isdefaultvalueavailable ()) {//detects if the parameter has a default value, if there is data to save the default value $dependencies [] = $ Param->getdefaultvalue (); } else {//Get the type prompt for the parameter, see if it is null, return the Reflectclass object///Here for example, for example a constructor for such __construct (Db $db); This returns the reflection of the db class $c = $param->getclass (); CreateInstance Instance Store class name $dependencies [] = instance::of ($c = = = null? NULL: $c->getname ()); }}}//Stored $this->_reflections[$class] = $reflection; $this->_dependencies[$class] = $dependencies; return [$reflection, $dependencies];}
The main function of this method is to parse the dependency information, mainly to obtain the information of the class's constructor, so that the constructor can be called to create an instance.
Resilvedependencies Method Invocation
This method is mainly to instantiate dependencies, that is, to create a constructor parameter object, not too much to repeat
protected function Resolvedependencies ($dependencies, $reflection = null) { foreach ($dependencies as $index = $ Dependency) { //in Getdependencies that parse dependency information, some parameters do not have default values, but instead create instance objects //The parameter objects that will instantiate these instance objects to the real constructor if ($dependency instanceof Instance) { if ($dependency->id!== null) { $dependencies [$index] = $this- >get ($dependency->id); } ElseIf ($reflection!== null) { $name = $reflection->getconstructor ()->getparameters () [$index]->getname (); $class = $reflection->getname (); throw new Invalidconfigexception ("Missing required parameter \" $name \ "when instantiating \" $class \ "."); } } return $dependencies;}
Summarize
In the above source code can basically see a few reflection of the application, and what is reflected in the end, what role? Presumably read the above will have a little understanding, well, in fact, the meaning of the name,
is the reflection class information, its role is to get the information of the class, and PHP's reflection class also provides a lot of interface functions for use, when used to check the official website manual.
The above also looks at the Di container in the YII2 framework to create objects, here still want to be able to tell a little bit about the beginning of the sample code, its first in the container to inject the database connection class, Finder class, listener class, and the Finder class constructor depends on the
The database connection class, the listener class relies on the Finder class, which is obtained by obtaining a dependency information method that can be used to know that the constructor will remove the dependent object information and then call the parse dependency information back to call the Get method to return the injected relationship to the instantiated object implementation.
The above is the whole content of this article, I hope that everyone's learning has helped, more relevant content please pay attention to topic.alibabacloud.com!