V
V
Veronika Stepanovna2016-05-21 19:08:14
Yii
Veronika Stepanovna, 2016-05-21 19:08:14

How does Yii::app() work?

As far as I understand, Yii::app() is a method through which you can access the services registered in the framework. What is DI and Service Locator I know and understand that Yii::app() implements access to them. But how exactly? How does the name of the service get into the app() method, how to implement it?

Answer the question

In order to leave comments, you need to log in

2 answer(s)
P
Pavel Volintsev, 2016-05-21
@sargss

1. Initialization of Yii::app()
Look, there are such lines in the www/index.php file

1. $config = APP_PATH . '/protected/config/main.php';
2. $app = \Yii::createWebApplication($config); // @var CWebApplication $app
3. $app->run();

When processing line 2, the code is executed
1. class YiiBase {
2. {
3.     // ... другой код
4. 
5.     public static function createWebApplication($config=null)
6.     {
7.         return self::createApplication('CWebApplication',$config);
8.     }
9.
10.    public static function createApplication($class,$config=null)
11.    {
12.        return new $class($config);
13.    }
14. }

In line 12, taking into account dynamic binding, it is executed. return new CWebApplication($config);
If we go through the parent classes, we can find that
further
1. abstract class CApplication extends CModule
2. {
3.     // ... другой код
4. 
5.     public function __construct($config=null)
6.     {
7.         Yii::setApplication($this);
8.         // ... и другой код
9.     }
10. }

In line 7 it is called Yii::setApplication($this);, and if you look at the class Yiiand its parent YiiBase, you can see how the variable for the construction is eventually initializedYii::app()
class YiiBase {
{
    private static $_app;
    public static function setApplication($app) // тут определяется значение self::$_app для Yii::app()
    {
        if(self::$_app===null || $app===null)
            self::$_app=$app;
        else
            throw new CException(Yii::t('yii','Yii application can only be created once.'));
    }
    public static function app() // тут можно прочитать значение self::$_app через Yii::app()
    {
        return self::$_app;
    }
}

Now it is clear that when the type entity was initialized, CWebApplicationthis entity was set to a private variable YiiBase::$_app, which is available through the call Yii::app()
This was initialization
2. Using Yii::app()->module or Yii::app()->component Take another
look at the classCApplication
abstract class CApplication extends CModule
{
    public function __construct($config=null)
    {
        Yii::setApplication($this);

        // ... другой код

        $this->configure($config);

        // ... другой код
    }
}

The method configure($config)prepares data that will be needed later for such calls as (for example) Yii::app()->db
Let's look at the Module class, in which the logic of such calls is implemented
abstract class CModule extends CComponent
{
    public function configure($config) // сохранить всё что передали по переменным
    {
        if(is_array($config))
        {
            foreach($config as $key=>$value)
                $this->$key=$value;
        }
    }

    public function __get($name) // если кто-то пытается вызвать несуществующее свойство, например Yii::app()->db
    {
        if($this->hasComponent($name)) // проверить что есть настройки или готовая сущность компоненты
            return $this->getComponent($name); // вернуть сущность компоненты
        else
            return parent::__get($name);
    }

    public function hasComponent($id) // проверить что есть настройки или готовая сущность компоненты
    {
        return isset($this->_components[$id]) || isset($this->_componentConfig[$id]);
    }

    public function getComponent($id,$createIfNull=true) // вернуть сущность компоненты
    {
        if(isset($this->_components[$id])) // если есть готовая сущность компоненты, вернуть её
            return $this->_components[$id];
        elseif(isset($this->_componentConfig[$id]) && $createIfNull)
        {
            $config=$this->_componentConfig[$id];
            if(!isset($config['enabled']) || $config['enabled'])
            {
                unset($config['enabled']);
                $component=Yii::createComponent($config); // создать новую сущность компоненты
                $component->init();
                return $this->_components[$id]=$component; // сохранить и вернуть её
            }
        }
    }
}

Let's try to decipher the call Yii::app()->db
As I have already shown, Yii::app()it is an entity of type CWebApplication, and it does not have a public property $db, so PHP calls the magic method __get()from the base class CModule. (Look in the documentation "magic methods")
So, the property CWebApplication->dbdoes not exist and is called CModule->__get('db'), then the code considers that the component may be called.
The method CModule->hasComponent('db')checks that some settings were previously set specified through the configuration file protected/config/main.phpor otherwise. If so, then is called CModule->getComponent('db', ...), which calls Yii::createComponent($config), where $configare the found settings of the specified component, for example, the database connection parameters for the db component
Let's see what it doesYii::createComponent($config)
class YiiBase
{
    public static function createComponent($config)
    {
        // посмотри сам, тут интересно
    }
}

Complicated method. Its essence is instantiation of a new entity of some class, 5 or 6 ways. The fact is that this method CModule::createComponent()can be called from anywhere and it has a lot of options for passing parameters.
So, CModule::createComponent()created and returned a new entity. And at the exit from the method, the CModule::getComponent()resulting entity is written to the array CModule->_componentsunder the name 'db'.
All subsequent calls Yii::app()->dbwill check for the presence of the instantiated entity in the array and use it CModule->_components['db']if found there via the configuration file protected/config/main.php
B. Component is initialized only once per PHP application cycle
I hope I have explained the lazy component initialization mechanism clearly

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question