1. Инициализация Yii::app()
Смотри, в файле www/index.php такие строки
1. $config = APP_PATH . '/protected/config/main.php';
2. $app = \Yii::createWebApplication($config); // @var CWebApplication $app
3. $app->run();
При отработке строки 2 выполняется код
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. }
В строке 12 с учётом динамического связывания выполняется
return new CWebApplication($config);
Если пройти по родительским классам, то можно найти, что
class CWebApplication extends CApplication ...
и далее
1. abstract class CApplication extends CModule
2. {
3. // ... другой код
4.
5. public function __construct($config=null)
6. {
7. Yii::setApplication($this);
8. // ... и другой код
9. }
10. }
В строке 7 вызывается
Yii::setApplication($this);
, а если посмотреть класс
Yii
и его родителя
YiiBase
, то можно увидеть как в итоге инициализируется переменная для конструкции
Yii::app()
class Yii extends YiiBase { }
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;
}
}
Теперь понятно, что при инициализации сущности типа
CWebApplication
эта сущность установилась в приватную переменную
YiiBase::$_app
, которая доступна через вызов
Yii::app()
Это была инициализация
2. Использование Yii::app()->module или Yii::app()->component
Ещё раз посмотри на класс
CApplication
abstract class CApplication extends CModule
{
public function __construct($config=null)
{
Yii::setApplication($this);
// ... другой код
$this->configure($config);
// ... другой код
}
}
В методе
configure($config)
происходит подготовка данных, которые понадобятся позже для таких вызовов как (к примеру)
Yii::app()->db
Давай посмотрим на класс Module, в котором и реализуется логика таких вызовов
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; // сохранить и вернуть её
}
}
}
}
Попробуем расшифровать вызов
Yii::app()->db
Как я уже показал,
Yii::app()
- это сущность типа
CWebApplication
, а у неё нет публичного свойства
$db
, поэтому PHP вызывает магический метод
__get()
из базового класса
CModule
. (Посмотри в документации "магические методы")
Итак, свойства
CWebApplication->db
не существует и вызывается
CModule->__get('db')
, далее код считает, что, возможно производится вызов компоненты.
Метод
CModule->hasComponent('db')
проверяет, что ранее были заданы какие-то настройки указанной через файл конфигурации
protected/config/main.php
или иным способом. Если так, то то вызывается
CModule->getComponent('db', ...)
, который вызывает
Yii::createComponent($config)
, где
$config
- это найденные настройки указанной компоненты, например, параметры соединения с базой данных для компоненты db
Посмотрим, что делает
Yii::createComponent($config)
class YiiBase
{
public static function createComponent($config)
{
// посмотри сам, тут интересно
}
}
Cложный метод. Суть его в инстанциировании новой сущности какого-то класса, 5 или 6 способов. Дело в том, что этот метод
CModule::createComponent()
может быть вызван откуда угодно и у него куча вариантов передачи параметров.
Итак,
CModule::createComponent()
создал и вернул новую сущность. И на выходе из метода
CModule::getComponent()
полученная сущность записывается в массив
CModule->_components
под именем 'db'.
Все последующие вызовы
Yii::app()->db
будут проверять наличие инстанциинованной сущности в массиве
CModule->_components['db']
и использовать его, если он там найден
Заключение:
Вызов Yii::app()->db
А. Динамически инициализирует компоненту, по мере необходимости
Б. Настраивает её данными, которые в частновти можно определить через файл конфигурации protected/config/main.php
В. Инициализируют компоненту только один раз за цикл работы PHP приложения
Надеюсь я понятно изложил механизм ленивой инициализации компонент