今天我们继续来探索Component.php
/**
* Makes sure that the behaviors declared in [[behaviors()]] are attached to this component. *确保在声明的行为[behaviors()]]安装此组件。
*/
public function ensureBehaviors()
{
// 如果$this->_behaviors为空,获取$this->behaviors()中的behaviors,并存储到$this->_behaviors数组中
if ($this->_behaviors === null) {
$this->_behaviors = [];
foreach ($this->behaviors() as $name => $behavior) {
$this->attachBehaviorInternal($name, $behavior);
}
}
}
/**
* Attaches a behavior to this component.
*
* 内部使用的为该对象添加behavior的方法
*
* @param string|integer $name the name of the behavior. If this is an integer, it means the behavior
* is an anonymous one. Otherwise, the behavior is a named one and any existing behavior with the same name
* will be detached first.
* @param string|array|Behavior $behavior the behavior to be attached
* @return Behavior the attached behavior.
*/
private function attachBehaviorInternal($name, $behavior)
{
if (!($behavior instanceof Behavior)) {
// $behavior不是Behavior对象,就认为是配置,通过它创建一个
$behavior = Yii::createObject($behavior);
}
if (is_int($name)) {
$behavior->attach($this);
$this->_behaviors[] = $behavior;
} else {
if (isset($this->_behaviors[$name])) {
// 存在就先解绑掉
$this->_behaviors[$name]->detach();
}
$behavior->attach($this);
$this->_behaviors[$name] = $behavior;
}
return $behavior;
}
下面我们来看一下Application.php
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
use Yii;
abstract class Application extends Module
{
const EVENT_BEFORE_REQUEST = 'beforeRequest';
/**
* @event Event an event raised after the application successfully handles a request (before the response is sent out). *事件引发的事件后,该应用程序成功处理请求的事件(发出的响应)
*/
const EVENT_AFTER_REQUEST = 'afterRequest';
/**
* Application state used by [[state]]: application just started.
*/
const STATE_BEGIN = 0;
/**
* Application state used by [[state]]: application is initializing. *应用程序正在初始化:由[state]使用的应用程序状态
*/
const STATE_INIT = 1;
/**
* Application state used by [[state]]: application is triggering [[EVENT_BEFORE_REQUEST]]. *应用程序触发[EVENT BEFORE_REQUEST]:由[state]使用应用程序状态。
*/
const STATE_BEFORE_REQUEST = 2;
/**
* Constructor.
* @param array $config name-value pairs that will be used to initialize the object properties.
* Note that the configuration must contain both [[id]] and [[basePath]].
* @throws InvalidConfigException if either [[id]] or [[basePath]] configuration is missing.
*/
public function __construct($config = [])
{
// 将自身的实例绑到Yii的$app上
Yii::$app = $this;
// 将自身加入到loadedModules中
$this->setInstance($this);
// 设置状态为刚开始
$this->state = self::STATE_BEGIN;
// 做预处理,包括设置alias和merge核心components的配置
$this->preInit($config);
$this->registerErrorHandler($config);
Component::__construct($config);
}
/**
* Pre-initializes the application.
* This method is called at the beginning of the application constructor.
* It initializes several important application properties.
* If you override this method, please make sure you call the parent implementation. *预先初始化应用程序。 这种方法被称为在应用程序构造的开始。 *它初始化一些重要的应用程序属性。 *如果您覆盖此方法,请确保您调用父类的实现。
* @param array $config the application configuration
* @throws InvalidConfigException if either [[id]] or [[basePath]] configuration is missing.
*/
public function preInit(&$config)
{
// 使用了&符号,表示$config的修改会保留
if (!isset($config['id'])) {
throw new InvalidConfigException('The "id" configuration for the Application is required.');
}
if (isset($config['basePath'])) {
// 项目的root路径
$this->setBasePath($config['basePath']);
// 用完删掉
unset($config['basePath']);
} else {
throw new InvalidConfigException('The "basePath" configuration for the Application is required.');
}
if (isset($config['vendorPath'])) {
$this->setVendorPath($config['vendorPath']);
unset($config['vendorPath']);
} else {
// 不存在,就设置默认值
// set "@vendor"
$this->getVendorPath();
}
if (isset($config['runtimePath'])) {
$this->setRuntimePath($config['runtimePath']);
unset($config['runtimePath']);
} else {
// 不存在,就设置默认值
// set "@runtime"
$this->getRuntimePath();
}
if (isset($config['timeZone'])) {
$this->setTimeZone($config['timeZone']);
unset($config['timeZone']);
} elseif (!ini_get('date.timezone')) {
// 默认时区是零时区
$this->setTimeZone('UTC');
}
// merge core components with custom components
foreach ($this->coreComponents() as $id => $component) {
if (!isset($config['components'][$id])) {
// 如果配置中没有配置相应的核心component,就赋给它
$config['components'][$id] = $component;
} elseif (is_array($config['components'][$id]) && !isset($config['components'][$id]['class'])) {
// 如果存在相应的核心component,但没有定义它的class,就直接赋到class的key上
$config['components'][$id]['class'] = $component['class'];
}
}
}
/**
* @inheritdoc
*/
public function init()
{
$this->state = self::STATE_INIT;
$this->bootstrap();
}
/**
* Registers the errorHandler component as a PHP error handler. *注册的errorHandler组件作为PHP错误处理程序。
* @param array $config application config
*/
protected function registerErrorHandler(&$config)
{
// YII_ENABLE_ERROR_HANDLER,在BaseYii中被定义为true
if (YII_ENABLE_ERROR_HANDLER) {
if (!isset($config['components']['errorHandler']['class'])) {
echo "Error: no errorHandler component is configured.\n";
exit(1);
}
// 其实质是将$config['components']['errorHandler']的内容设置到了$this->_definitions['errorHandler']中
$this->set('errorHandler', $config['components']['errorHandler']);
// 删除掉errorHandler的配置内容
unset($config['components']['errorHandler']);
$this->getErrorHandler()->register();
}
}
/**
* Returns the directory that stores runtime files. * 返回存储运行时文件的目录。
* @return string the directory that stores runtime files.
* Defaults to the "runtime" subdirectory under [[basePath]].
*/
public function getRuntimePath()
{
if ($this->_runtimePath === null) {
// 不存在,就将其设置为basePath/runtime
$this->setRuntimePath($this->getBasePath() . DIRECTORY_SEPARATOR . 'runtime');
}
return $this->_runtimePath;
}
来源:https://www.cnblogs.com/taokai/p/5406387.html