How to register and create a component in Yii2

Source: Internet
Author: User
Today, I was going to study the implementation of the AR model of yii2.0, however, the plan couldn't keep up with the changes and suddenly wanted to look at the process of yii2.0 database component creation. Through the study of Yii source code, the process of registration and creation of YII components is learned, and it is found that the original Yii component is not created immediately after registration, but until the actual need to use a component to create the corresponding component instance. This article is about documenting the process of exploration.

To understand the registration and creation of YII components, of course, from the Yii portal file index.php, the entire file code is as follows:

<?phpdefined (' yii_debug ') or define (' Yii_debug ', true);d efined (' yii_env ') or define (' yii_env ', ' dev '); require (DIR . '/.. /.. /vendor/autoload.php '); require (DIR. '/.. /.. /vendor/yiisoft/yii2/yii.php '); require (DIR. '/.. /.. /common/config/bootstrap.php '); require (DIR. '/.. /config/bootstrap.php '); $config = Yii\helpers\arrayhelper::merge (Require (DIR. '/.. /.. /common/config/main.php '), Require (DIR. '/.. /.. /common/config/main-local.php '), Require (DIR. '/.. /config/main.php '), Require (DIR. '/.. /config/main-local.php ');(new Yii\web\application ($config))->run ();

You can see that the portal file introduces several configuration files and merges the contents of all the configuration files into the $config configuration array, and then uses this configuration array as a parameter to create an application instance. If you print this configuration array, you will see that the "components" subscript corresponds to the element containing the parameter information for the Yii component (only a small part here):

The information for these components is configured in the introduction of several configuration files, and Yii components are registered and created using these parameter information.

The next step is to instantiate the Yii\web\application class, the Yii\web\application class has no constructors, but it inherits the \yii\base\application class:

So the constructor for the \yii\base\application class is automatically executed:

Public Function construct ($config = []) {Yii:: $app = $this; static::setinstance ($this); $this->state = Self::state_beg In; $this->preinit ($config); $this->registererrorhandler ($config); Component::construct ($config);}

Here, by the way, the pre-initialization method, PreInit (), has the following code:

Public Function PreInit (& $config) {/* Here omit preprocessing operation code for $config array *//merge core components with custom components FOREAC H ($this->corecomponents () as $id = + $component) {  if (!isset ($config [' components '] [$id]) {   $config [' Components ' [$id] = $component;  } ElseIf (Is_array ($config ["Components"] [$id]) &&!isset ($config [' components '] [$id] [' class ']) {   $config [' Components '] [$id] [' class '] = $component [' class '];  } }}

This function makes some preprocessing operations (omitted here) for the configuration array passed to the constructor, and finally $config the $config array using the array returned by the Corecomponents () method, which is the Corecomponents () method:

Public Function corecomponents () {return [  ' log ' = [' class ' = ' Yii\log\dispatcher '],  ' view ' and ' = ' Class ' = ' Yii\web\view '],  ' formatter ' = [' class ' = ' Yii\i18n\formatter '],  ' i18n ' = ' = ' > ' yii\i18n\i18n ', '  mailer ' = [' class ' = ' Yii\swiftmailer\mailer '],  ' urlmanager ' = ' = ' > ' Yii\web\urlmanager ', '  assetmanager ' = [' class ' = ' Yii\web\assetmanager '],  ' security ' and ' = ' Class ' = ' yii\base\security '],];}

In fact, some of the core components of the configuration, that is to say that these components can not be configured in the configuration file, Yii will automatically register.

Well, back to the constructor of the \yii\base\application class, this function finally calls the constructor of the \yii\base\component class, but the \yii\base\component class is not a constructor, but it inherits the \yii\ Base\object class:

The constructor for the \yii\base\object class is also executed automatically:

Public Function construct ($config = []) {if (!empty ($config)) {  yii::configure ($this, $config);} $this->init ();}

This is mostly called the static method of the \yii\baseyii class configure ():

public static function Configure ($object, $properties) {foreach ($properties as $name = $value) {$object $na  me = $value; } return $object;}

This method is the $config array in the Loop entry file (new yii\web\Application($config))->run(); (the structure of this array is described in the first of this article), with the array key name as the object property name, and the corresponding key value as the object property value to be assigned operation. So when looping to component configuration parameters: $object->components = $value ($value is an array of configurations for all components), which is the assignment of the component properties of $object, that $ What is object of the class? Recalling the source of the original invocation, it is actually the object of the \yii\web\application class that needs to be instantiated in the portal file. However, this class and its ancestors do not have the components of this member variable Ah, not urgent, but also to carry out a succession of routines, along the inheritance of the Yii\web\application class on a layer to find \yii\web\ The application class eventually inherits the \yii\base\object class, and the \yii\base\object class is a supported property, so the Yii\web\application class also supports attributes (about properties, You can refer to my other blog post: Yii2 's properties), call the Setcomponents () method when the assignment operation cannot find the components member variable, and find out where the method is, and finally in its ancestor class \yii\di\ Servicelocator found the Setcomponents () method, yes, the application instance of the components of the assignment operation is actually called this method!

OK, now let's see setcomponents () What this method did:

Public Function setcomponents ($components) {foreach ($components as $id = = $component) {  $this->set ($id, $ component); }}

In fact, it is simple to loop through the configuration array of each component, call the Set () method, and the set () method is as follows:

Public function set ($id, $definition) {unset ($this->_components[$id]), if ($definition = = = null) {  unset ($this-& gt;_definitions[$id]);  Return } if (Is_object ($definition) | | is_callable ($definition, True)) {  //an object, a class name, or a PHP callable  $t his->_definitions[$id] = $definition; } elseif (Is_array ($definition)) {  //a configuration array  if (Isset ($definition [' class ')]) {   $this->_ definitions[$id] = $definition;  } else {   throw new Invalidconfigexception ("The configuration for the \" $id \ "component must contain a \" class\ "element. ");  } } else {  throw new Invalidconfigexception ("Unexpected configuration type for the \" $id \ "component:". GetType ($definition)); }}

In fact, the component configuration is stored in the $_definitions Private member variable (that is, registration), then? And then there's no more.

For a long time, the original Yii when creating an application instance is simply registering the component, and does not actually create the component, then when is the component instance created? Where do you create them? Don't worry. From the process deduced above, we know that the \yii\di\servicelocator class is the ancestor class of the \yii\web\application class, so in fact, the application example of Yii is actually a service locator, such as when we want to access the database components, We can visit: Yii:: $app->db, this yii:: $app is a yii application instance, that is, an instance of the \yii\web\application class, but the \yii\web\application class and its parent class, The ancestor class could not find the DB attribute. Haha, don't forget that PHP will call the Magic Method get () when it does not read the Class property, so we start looking for the Get () method in the Ancestor class nearest to the \yii\web\application inheritance, and finally found it in the \yii\di\servicelocator class. In other words, Yii:: $app->db will eventually call the Get () method in the \yii\di\servicelocator class:

Public function Get ($name) {if ($this->has ($name)) {  return $this->get ($name);} else {  return parent::get ($name); }}

The Get () method first calls the has () method (which no longer has the code) to determine if the component is registered, and if it is registered, the Get () method is called:

Public function Get ($id, $throwException = True) {if (Isset ($this->_components[$id]) {  return $this->_ components[$id]; } if (Isset ($this->_definitions[$id])) {  $definition = $this->_definitions[$id];  if (Is_object ($definition) &&! $definition instanceof Closure) {   return $this->_components[$id] = $ definition;  } else {   return $this->_components[$id] = Yii::createobject ($definition);  }} elseif ($throwException) {  throw new Invalidconfigexception ("Unknown component ID: $id"); } else {  return null;}}

Where the private member variable $_components is the instance of a component that has already been created, and if it is found that the component has already been created, it returns the component example directly, otherwise it uses the registration information of the corresponding component in $_definitions, calling \yii\baseyii::createobject () method for component creation, this method eventually invokes the get () method that relies on the injection container \yii\di\container, followed by the process of relying on injection to create the object, about which the process has been explained in my previous Article blog post, Refer to: Yii2 Dependency Injection and Dependency injection container.

Well, the whole process of registering and creating Yii components is like this. Finally, in fact, Yii creates an application instance with the registration of each component, that is, the configuration information of the component is stored in the private member variable $_definitions of the \yii\di\servicelocator class, and is not actually created. Wait until the program is really needed to use a component in the process, based on the registration information that the component holds in $_definitions, use the Dependency injection container \yii\di\container to create the component instance, and then save the created instance to the private member variable $_ Components so that the next time you access the same component, you can return to the component instance directly, and no longer need to perform the creation process. Yii This component registration and creation mechanism is actually helpful, imagine, if the application instance created when the creation of all components, will greatly increase the time the application instance is created, each time the user refreshes the page is created by the application instance, that is, the user every refresh page is very slow, This user experience is very bad, and in many cases there are many components are not used, but we still spend a lot of time to create these components, it is very unwise, so Yii's approach is: first to save the component parameter information, need to use which components to create the corresponding instance, Greatly save the time of application creation, but also save the memory, this idea is very worthy of our learning!

Summarize

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.