A detailed description of the attribute injection and method injection of component behavior in the YII framework of PHP, YII framework _php Tutorial

Source: Internet
Author: User
Tags php framework

A detailed description of the attribute injection and method injection of component behavior in the PHP framework of YII, YII framework


Behavior properties and method injection principles

We learned from the above that the intent of the act is to inject its own attributes and methods into the classes that are attached. So how does Yii inject the properties and methods of a behavior yii\base\behavior into a yii\base\component? For attributes, this is done through the __get () and __set () magic methods. For methods, it is through the __call () method.

Injection of attributes

Take read as an example, what does Yii do behind the scenes if it accesses $Component->property1? Take a look at Yii\base\component::__get ()

Public Function __get ($name) {  $getter = ' get '. $name;  if (Method_exists ($this, $getter)) {    return $this $getter ();  } else {    //Note the content of this else branch is exactly the same as yii\base\ Object::__get ()    //Difference    $this->ensurebehaviors ();    foreach ($this->_behaviors as $behavior) {      if ($behavior->cangetproperty ($name)) {        //attribute must be public in the behavior. Otherwise it is impossible to access it through the following form.        return $behavior $name;  }} if (method_exists ($this, ' Set '. $name)) {    throw new invalidcallexception (' Getting write-only property: ').      Get_class ($this). '::' . $name);  } else {    throw new unknownpropertyexception (' Getting unknown property: '.      Get_class ($this). '::' . $name);}  }

Focus on the differences between Yii\base\compoent::__get () and Yii\base\object::__get (). That is, for processing after the Getter function is undefined, yii\base\object throws the exception directly, telling you that the property you want to access does not exist. But yii\base\component is the attribute of the behavior that is not injected after the getter is not present:

First, the $this->ensurebehaviors () is called. This method has been described earlier, mainly to ensure that the behavior is bound.
After ensuring that the behavior has been bound, start traversing the $this->_behaviors. Yii stores the behavior of all binding classes in the yii\base\compoent::$_behaviors[] array.
Finally, the behavior of Cangetproperty () determines whether this property is a readable property of the bound behavior, and if so, returns this property of the behavior $behavior->name. Completes the read of the property. As for Cangetproperty () already in: Ref::p The Roperty section has been briefly described, followed by a targeted introduction.
For setter, the code is similar, here is no space.

Injection of methods

Similar to the injection of attributes through the __get () __set () Magic method, Yii implements the injection of the methods in the behavior by means of the __call () Magic Method:

Public Function __call ($name, $params) {  $this->ensurebehaviors ();  foreach ($this->_behaviors as $object) {    if ($object->hasmethod ($name)) {      return Call_user_func_array ([ $object, $name], $params);    }  }  throw new Unknownmethodexception (' Calling unknown Method: '.    Get_class ($this). ":: $name ()");}

As can be seen from the above code, YII first calls the $this->ensurebehaviors () to ensure that the behavior is bound.

Then, it is also the traversal yii\base\component::$_behaviros[] array. Determine whether a method exists by using the Hasmethod () method. If the method being invoked in the bound behavior exists, it is invoked using PHP's Call_user_func_array (). As for the Hasmethod () method, we'll talk about it later.

Access control for injected properties and methods

In the preceding section we cite specific examples of whether public and private, protected members in the behavior are accessible in the class being bound. Here we parse the reason from the code level.

In the above content, we know that an attribute can be inaccessible, mainly looking at the behavior of Cangetproperty () and Cansetproperty (). And a method can not be called, mainly see the behavior of the Hasmethod (). Since Yii\base\behavior inherits from our old friend Yii\base\object, the three judgments mentioned above are in fact the code in Object. Let's look at it one by one:

Public Function Cangetproperty ($name, $checkVars = True) {  return method_exists ($this, ' get '. $name) | | $checkVars &am p;&    property_exists ($this, $name);} Public Function Cansetproperty ($name, $checkVars = True) {  return method_exists ($this, ' Set '. $name) | | $checkVars &am p;&    property_exists ($this, $name);} Public Function Hasmethod ($name) {  return method_exists ($this, $name);}

These three methods are really not complicated. In this respect, we can draw the following conclusions:

When a property is read (written) to a component bound behavior, it can be accessed if the behavior defines a getter (setter) for the property. Alternatively, if the behavior does have this member variable to pass the above judgment, at this point, the member variable can be public, private, protected. However, only the member variables of public can be accessed correctly. The reason is explained in the above-mentioned principle of injection.
When calling a method of the behavior of the component binding, if the behavior already defines the method, it can be judged by the above. At this point, this method can be public, private, protected. However, only public methods can be called correctly in the end. If you understand the reason for the previous paragraph, it will be understood here.


Dependency Injection Container
A dependency injection (Dependency Injection,di) container is an object that knows how to initialize and configure the object and all of its dependent objects. Martin's article has explained why DI containers are useful. Here we mainly explain the use of the DI container provided by YII.

Dependency Injection

Yii provides DI container properties through the Yii\di\container class. It supports several types of dependency injection as follows:

    • construction method injection;
    • Setter and attribute injection;
    • PHP callback injection.
    • Construct Method Injection

With the help of parameter type hints, the DI container implements the construction method injection. When a container is used to create a new object, the type hint tells it what class or interface to depend on. The container attempts to obtain an instance of the class or interface on which it depends, and then injects it into the new object through the constructor. For example:

Class foo{public  function __construct (Bar $bar)  {  }} $foo = $container->get (' Foo ');//The above code is equivalent to: $bar = New Bar; $foo = new Foo ($bar);

Setter and attribute Injection

Setter and attribute injection are supported through configuration. When registering a dependency or creating a new object, you can provide a configuration that is provided to the container for use by the appropriate Setter or property injection dependency. For example:

Use Yii\base\object;class Foo extends object{public  $bar;  Private $_qux;  Public Function Getqux ()  {    return $this->_qux;  }  Public Function Setqux (Qux $qux)  {    $this->_qux = $qux;  }} $container->get (' Foo ', [], [  ' bar ' = = $container->get (' Bar '),  ' Qux ' + $container->get (' Qux '),]);

PHP Callback Injection

In this case, the container will use a registered PHP callback to create a new instance of the class. Callbacks are responsible for resolving dependencies and injecting them appropriately into newly created objects. For example:

$container->set (' Foo ', function () {  return new Foo (new Bar);}); $foo = $container->get (' foo ');

Registering dependency relationships

The

can register dependencies with Yii\di\container::set (). Registration uses a dependency name and a definition of a dependency relationship. A dependency name can be a class name, an interface name, or an alias. The definition of a dependency can be a class name, a configuration array, or a PHP callback.

$container = new \yii\di\container;//Register a dependency of the same name, this can be omitted. $container->set (' yii\db\connection ');//Register an interface//When a class relies on this interface, the corresponding class is initialized as a dependent object. $container->set (' yii\mail\mailinterface ', ' yii\swiftmailer\mailer ');//Register an alias. You can use the $container->get (' foo ') to create a Connection instance $container->set (' foo ', ' yii\db\connection ');//Register a class by configuration//through When the Get () is initialized, the configuration will be used. $container->set (' yii\db\connection ', [' dsn ' = ' mysql:host=127.0.0.1;dbname=demo ', ' username ' = ' root ', ' pa ' ssWOrd ' + ', ' charset ' = ' utf8 ',]);//Register an alias with the configuration of the class//In this case, you need to specify this class by a "class" element $container->set (' db ', [' CL ' Yii\db\connection ', ' dsn ' = ' mysql:host=127.0.0.1;dbname=demo ', ' username ' = ' root ', ' password ' =&G T ', ' charset ' = ' utf8 ',]);//Register a PHP callback//each time the call $container->get (' db '), the callback function will be executed. $container->set (' db ', function ($container, $params, $config) {return new \yii\db\connection ($config);}); /Register a component instance//$container->get (' Pagecache ') will return the same instance each time it is called. $container-≫set (' Pagecache ', new Filecache); 

Tip: If the dependency name and dependency definitions are the same, you do not need to register the dependency with the DI container.
A dependency that is registered through set () will produce a new instance each time it is used. You can use Yii\di\container::setsingleton () to register a singleton dependency relationship:

$container->setsingleton (' yii\db\connection ', [  ' dsn ' = ' Mysql:host=127.0.0.1;dbname=demo ',  ' Username ' + ' root ',  ' password ' + ', '  charset ' = ' utf8 ',]

Resolving dependencies

Once you have registered a dependency, you can use the DI container to create a new object. The container automatically resolves the dependency, instantiating the dependency and injecting the newly created object. The dependency resolution is recursive, and if there are other dependencies in one dependency, the dependencies will be resolved automatically.

You can use Yii\di\container::get () to create a new object. The method receives a dependency name, which can be a class name, an interface name, or an alias. The dependency name may be registered through set () or Setsingleton (). You can optionally provide a constructor argument list for a class and a configuration to configure the newly created object. For example:

"DB" is an alias previously defined $db = $container->get (' db ');//equivalent to: $engine = new \app\components\searchengine ($apiKey, [' type ' =&G T 1]); $engine = $container->get (' App\components\searchengine ', [$apiKey], [' type ' = + 1]);

Behind the code, the DI container does much more work than creating objects. The container first checks the constructor of the class, finds the dependent class or interface name, and then automatically recursively resolves the dependencies.

The following code shows a more complex example. The Userlister class relies on an object that implements the Userfinderinterface interface, and the Userfinder class implements the interface and relies on a Connection object. All of these dependencies are defined by the type hint of the class constructor parameter. With the registration of property dependencies, the DI container can automatically resolve these dependencies and create a new Userlister instance through a simple get (' Userlister ') call.

namespace app\models;use yii\base\object;use yii\db\connection;use yii\di\container;interface userfinderinterface{function Finduser ();}  Class Userfinder extends Object implements userfinderinterface{public $db;    Public function __construct (Connection $db, $config = []) {$this->db = $db;  Parent::__construct ($config);  } public Function Finduser () {}}class Userlister extends object{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 ');//equivalent to: $db = new \yii\db\connection ([' DSN ' = ' ... '] ); $finder = new Userfinder ($db); $lister = new Userlister ($finder); 

The application in practice

When the yii.php file is introduced into the application's portal script, Yii creates a DI container. This DI container can be accessed via Yii:: $container. When Yii::createobject () is called, this method actually calls the container's Yii\di\container::get () method to create a new object. As mentioned above, the DI container automatically resolves the dependency (if any) and injects it into the newly created object. Because Yii uses Yii::createobject () to create new objects in most of its core code, you can customize these objects globally by using Yii:: $container.

For example, you can globally customize the default number of paging buttons in Yii\widgets\linkpager:

\yii:: $container->set (' Yii\widgets\linkpager ', [' maxbuttoncount ' = 5]);

So if you use this pendant in a view with the following code, its Maxbuttoncount property is initialized to 5 instead of the default value 10 defined in the class.

Echo \yii\widgets\linkpager::widget ();

However, you can still override the values set by the DI container:

Echo \yii\widgets\linkpager::widget ([' maxbuttoncount ' = 20]);

Another example is the benefit of using the automatic construction method injection in the DI container. Suppose your controller class relies on some other object, such as a hotel booking service. You can declare dependencies through a constructor parameter, and then let the DI container help you resolve this dependency automatically.

namespace App\controllers;use yii\web\controller;use App\components\bookinginterface;class HotelController extends controller{  protected $bookingService;  Public function __construct ($id, $module, Bookinginterface $bookingService, $config = [])  {    $this Bookingservice = $bookingService;    Parent::__construct ($id, $module, $config);  }}

If you access this controller from the browser, you will see an error message reminding you that bookinginterface cannot be instantiated. This is because you need to tell the DI container how to handle this dependency.

\yii:: $container->set (' app\components\bookinginterface ', ' app\components\bookingservice ');
Now if you access the controller again, an instance of App\components\bookingservice will be created and injected into the controller's constructor as a third parameter.

When to register a dependency

Because dependencies need to be addressed when creating new objects, their registrations should be completed as early as possible. The following are recommended practices:

If you are a developer of an application, you can register dependencies in the application's portal script or script introduced by the portal script.
If you are a developer who can redistribute extensions, you can register dependencies in the extended boot class.
Summarize

Dependency Injection and service locators are popular design patterns that enable you to build software in a fully decoupled and test-ready style. It is highly recommended that you read Martin's article and have a deeper understanding of dependency injection and service locator.

YII implements its service locator on top of the dependent on (DI) container. When a service locator tries to create a new object instance, it forwards the call to the DI container. The latter will automatically resolve the dependency as described earlier in this article.

Articles you may be interested in:

    • The method of removing the binding behavior of a component in PHP's YII framework
    • The definition and binding methods of behavior in the YII framework of PHP
    • A detailed approach to using behavioral behaviors in the PHP yii framework
    • In-depth explanation of properties in the Yii framework of PHP
    • PHP's YII framework uses database configuration and SQL Operations example tutorials
    • In-depth parsing of event events mechanism in the YII framework of PHP
    • Full interpretation of the log function in the YII framework of PHP
    • Yii uses find FindAll to find out how to implement a specified field
    • Analysis and modification of yii database by adding and deleting
    • YII PHP Framework Practical Introductory Tutorial (detailed)

http://www.bkjia.com/PHPjc/1111895.html www.bkjia.com true http://www.bkjia.com/PHPjc/1111895.html techarticle This paper introduces the attribute injection and method injection of the component behavior in the YII framework of PHP, the properties of YII framework behavior and the method injection principle .

  • 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.