YII2 essay (vii) Dependency injection-(3) Yii2 Dependency Injection

Source: Internet
Author: User
Tags exit in
Yii2 's Dependency Injection core code in Yii\di, under this package (folder) There are 3 files, respectively container.php (container), instance.php (instance), Servicelocator (service locator), now we discuss the first two , the service locator can understand the registry of a service, which does not affect our discussion of dependency injection, it is also an application of dependency injection.

Let's start with the code to explain how Yii2 uses dependency injection.

yii\base\application//This is YII2 dependency injection using the portal, parameter interpretation please refer to the source code, here is not much explanation public static function CreateObject ($type, Array $params =        []) {if (is_string ($type)) {//type is a string, it uses the type as the "raw material" of an object, passes it directly to the container and obtains the desired object through the container.    return static:: $container->get ($type, $params); } elseif (Is_array ($type) && isset ($type [' class ']) {//type is an array and has a class key that, after simple processing, gets the object's "raw material" and then the resulting "raw material"        Pass to the container and get the desired object through the container.        $class = $type [' class '];        unset ($type [' class ']);    return static:: $container->get ($class, $params, $type);    } elseif (Is_callable ($type, True)) {//If type is a callable structure, call return Call_user_func ($type, $params) directly; } elseif (Is_array ($type)) {//If type is an array and there is no ' class ' key value, throw an exception throw new Invalidconfigexception (' Object Configur    Ation must is an array containing a "class" element. '); } else {///In other cases, throws another exception, saying that type does not support a configuration type of throw new Invalidconfigexception ("Unsupported Configuration Type:".)    GetType ($type)); }}

By reading the above code, Yii::createobject () is the qualified "raw material" to the "container ($container)" To generate the target object, then the container is our "dependency injection" of the production object. So when was $container introduced (note that this is static:: $container, not self:: $container)? Remember the statement when you imported the YII framework on the homepage?

Import Yii framework require (__dir__. '/.. /vendor/yiisoft/yii2/yii.php ');

The code is as follows

Introduced the basic YII framework require (__dir__. '/baseyii.php ');//Just do the inheritance, here we left two times the development of the room, although very few can use the class Yii extends \yii\baseyii{}//settings automatically loaded spl_autoload_register ([' Yii ', ' AutoLoad '], true, true);//Register CLASSMAPYII:: $classMap = require (__dir__. '/classes.php ');//Register Container yii:: $container = new Yii\di\container ();

You look right! Is the last word, yii2 the realization of Yii\di\container to their own use. Next, let's talk about how containers are implemented.

Then the above static:: $container->get () method, before explaining the Get method, we need to understand the container's several properties, which will help to understand the implementation of get

$_singletons; A singleton array whose key value is the name of the class, and if the generated object is a singleton, save it in this array with a value of NULL, indicating that it has not yet been instantiated $_definitions;//definition array, whose key value is the name of the class, and the value is the "raw material" required to generate the class, in the set or Setsingleton to write $_params; parameter, whose key value is the name of the class, and the value is the additional "raw material" required to generate the class, written $_reflections at set or Setsingleton; Reflection, its key value is the name of the class, the value is the reflection handle of the object to be generated, when the object is generated to write $_dependencies;//dependency, its key value is the name of the class, the value is to generate the object before some of the necessary "raw materials", when the object is generated by the reflection function.

OK, if you are careful enough to understand some of the above properties, it is estimated that you have a general understanding of the Yii2 container, which is still starting from get.

Public function Get ($class, $params = [], $config = []) {if (Isset ($this->_singletons[$class])) {//See if the object to be generated is in a singleton, such as    The result is a direct return//Singleton return $this->_singletons[$class];    } elseif (!isset ($this->_definitions[$class])) {//If there is no definition of the class to generate, it is generated directly, and the majority of the YII2 itself goes this part, without registering anything in the container beforehand, So where is the configuration file registered? Do you remember the "service locator" at the beginning of the article?        We can see this in the service locator.    return $this->build ($class, $params, $config);    }//If the class has already been defined, the definition of the class is taken out $definition = $this->_definitions[$class]; if (Is_callable ($definition, True)) {//If the definition is a callable structure//The parameter is first integrated, and if there is a parameter of this class in $_params, if there is a parameter passed in with the incoming override defined in the same way /Then check whether the integrated parameters are dependent, that is, if there is a required parameter, if there is a direct throw exception, otherwise return the parameter. When checking dependencies, you need to determine if it is an instance (Instance), and if so, implement the instance.        Note: instance appears here.        $params = $this->resolvedependencies ($this->mergeparams ($class, $params));    The parameter is passed to the callable result, and the result $object = Call_user_func ($definition, $this, $params, $config); } elseif (Is_array ($definition)) {//If the definition is an array//the class to be generated is taken out $concRete = $definition [' class '];        Unregister this key value unset ($definition [' class ']);        Integrate definitions and configurations into new definitions $config = Array_merge ($definition, $config);        Integration Parameters $params = $this->mergeparams ($class, $params); If the incoming $class is exactly the same as the class in the definition, it is generated directly, the build first parameter is guaranteed to be the real class name, and the incoming $type may be the alias if ($concrete = = = $class) {$OBJEC        t = $this->build ($class, $params, $config);        } else {//if it is an alias, then callback itself, generating the object, because the class at this time may also be an alias $object = $this->get ($concrete, $params, $config); }} elseif (Is_object ($definition)) {//If the definition is an object, it means that the class is a singleton, saved to a singleton, and returned to the Singleton, here to think about it yourself, why is it an object is a singleton?        Imaginative achievement here inexpressible, mainly I also organize bad language how to explain it.    return $this->_singletons[$class] = $definition; } else {//Nothing is thrown exception throw new Invalidconfigexception ("Unexpected object definition type:".)    GetType ($definition));        }//Determine if the name of the class is in a singleton, and if so, put the generated object in the singleton if (Array_key_exists ($class, $this->_singletons)) {//Singleton $this->_singletons[$class]= $object; }//Returns the resulting object return $object;}

Study here, we find that the Get function is just a "portal", the main function in build

Create an object protected function build ($class, $params, $config) {//The reflection handle is obtained through the class name, and dependent (dependency is the desired parameter)//So the first parameter of the transport buile must be a valid "class name" as mentioned earlier    Otherwise, the list ($reflection, $dependencies) = $this->getdependencies ($class) will be directly error-directed;    The dependencies and parameters are configured, because dependencies may have default parameters, which overrides the default parameter, foreach ($params as $index = = $param) {$dependencies [$index] = $param;    }//Ensure that the dependencies are OK, all raw materials are okay, otherwise throw an exception $dependencies = $this->resolvedependencies ($dependencies, $reflection);    if (empty ($config)) {//If config is empty, return the target object return $reflection->newinstanceargs ($dependencies);  } if (!empty ($dependencies) && $reflection->implementsinterface (' yii\base\configurable ')) {//If the target object is Configurable interface//set $config as the last parameter (existing one would be overwritten) $dependencies [count        ($dependencies)-1] = $config;    Return $reflection->newinstanceargs ($dependencies);        } else {//other case $object = $reflection->newinstanceargs ($dependencies); foreach ($config as $name = $value) {$object, $name = $value;    } return $object; }}

OK, the build is over here, let's see how the container gets the reflection handle and dependencies

protected function Getdependencies ($class) {if (Isset ($this->_reflections[$class]) {//whether the target object has been resolved by return [$    this->_reflections[$class], $this->_dependencies[$class]]; } $dependencies = [];//initializes the dependent array $reflection = new Reflectionclass ($class);//Get the reflection of the target object, refer to the PHP manual $constructor = $ Reflection->getconstructor ();//Gets the constructor of the target object if ($constructor!== null) {//If the target object has a constructor, it means that he has dependencies//parsing all parameters, noting that the parameters are The order is left-to-right, ensuring that the dependency is also executed in this order, foreach ($constructor->getparameters () as $param) {if ($param->isdefaul Tvalueavailable ()) {//if the default value of the parameter is available $dependencies [] = $param->getdefaultvalue ();//Place the default value in the dependency} El SE {//if it is other $c = $param->getclass ();//Gets the type of the parameter, if the type of the parameter is not a class, is the base type, then returns NULL//If, is the base type, generates                A null instance, if it is not a base type, generates an instance of that class name.            Note: the instance is used here (Instance) $dependencies [] = instance::of ($c = = = = null? NULL: $c->getname ());  }}}//Save the reference for the next direct use.  $this->_reflections[$class] = $reflection;    Save the dependency for the next direct use $this->_dependencies[$class] = $dependencies; Return the result return [$reflection, $dependencies];}

Let's take a look at how containers ensure dependencies

protected function Resolvedependencies ($dependencies, $reflection = null) {//Get dependency foreach ($dependencies as $index            = = $dependency) {//If the dependency is an instance, because the processed dependencies are Instance objects if ($dependency instanceof Instance) { if ($dependency->id!== null) {//This instance has an ID, the object is generated by this ID and replaced with the original parameter $dependencies [$index] = $this->get ($            DEPENDENCY->ID); } elseif ($reflection!== null) {//If the reflection handle is not empty, note that this function is of type protected, so only the derived classes of this class or class can be accessed, but only two places in this class are used, one is get , if the target object is a callable result (is_callable), then $reflection===null, another build, $reflection not empty, this time represents the target object has a required parameter, but also is not an instance (instance object), this time represents the lack of the necessary "raw material" throws an exception//To get a response to the required parameter name, and throws an exception $name = $reflecti                On->getconstructor ()->getparameters () [$index]->getname ();                $class = $reflection->getname (); throw new Invalidconfigexception ("Missing required parameter \" $name \ "when instantiating \" $class \ ".");            }}}//Ensures all dependencies, returns all dependencies, if the target is is_callable ($definition, True), will not throw an exception, just instantiate the parameters of the instance type. return $dependencies;}

See here, we can understand how YII2 is using the container to implement "dependency injection", then there is a problem, how to guarantee the closure of the dependency? I think it's because yii2 that the existence of closures solves the problem of limitations, that there is no dependency, or that reliance is left to the developer to solve. Another YII2 container, if the argument is a closure, there will be an error, because of the dependency on the closure, when parsing the closure parameters, you will get $dependencies[]
= Instance::of ($c = = = null? NULL: $c->getname ()), a Closure instance is obtained, and when the instance is instantiated later, the problem arises, so when the object is implemented with the YII2 container, The implemented object cannot contain a closure parameter, and if there is a closure parameter, it must have a default value, or the person is guaranteed to pass in the closure parameter, bypassing the automatically generated statement.

The main functions of OK containers have these, other methods, set,setsingleton,has,hassingleton,clear know what meaning, and these methods are basically not used in the framework (can write exit in these functions, See if your page will be blank), or you can use the container to generate some of your own things to see the use of these functions yourself.

Finally, let's see what role instance plays.

yii\di\instance//very surprised, is to instantiate a self, notice that this is static, you may need to use this place public static function of ($id) {    return new static ( $id);} [/php] So what about the constructor of this function? [php]//prohibits external instantiation of protected function __construct ($id) {    //assignment id    $this->id = $id;}

In the container, the two methods of instance are used, stating that instance in the instance only ensures the availability of dependencies. In addition, instance provides other functions where get gets the instantiated object for the ID of the current instance, plus a static function ensure

Make sure that the $reference is $type type, and if it is not, throw an exception//use it more than once in the frame, please find it yourself//And if $type==null, he can also be used as a dependency injection portal, use the method please check the source code, By now you should be able to read the code yourself. public static function ensure ($reference, $type = null, $container = null) {    //...}

The above is YII2 essay (vii) Dependency injection-(3) Yii2 of the content of dependency injection, more relevant content please pay attention to topic.alibabacloud.com (www.php.cn)!

  • Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.