yii2框架-yii2的组件和服务定位器(四)
上一节主要是分析了yii2的自动加载函数,下面在分析一下yii2的核心组件与服务定位器。
这些核心的组件,我们可以在Yii::$app->request,或者Yii::$app->db,按照这个方式就可以获取组件的实例。那么这个过程原理是怎么样发生的呢?
大致的过程:首先在入口文件执行这一句代码
(new yiiwebApplication($config))->run();
在yiiwebApplication的类名文件中,yiiwebApplication继承yiiaseApplication,创建一个应用实例,初始化一些别名,检查配置文件,并将这一个应用实例赋值给Yii::$app这个静态变量,那么在整一个请求访问的过程中,Yii::$app就相当于应用实例存在的。
当我们执行Yii::$app->request获取请求的实例时,但由于$request的属性在这个应用实例中并没有声明的,包括在父级的基础类中也是没有的,按照正常情况,肯定是会发送错误的。因此之所以能够请求到这个属性,就要说一说yii2框架的属性了
我们知道,在读取和写入对象的一个不存在的成员变量时, __get() __set() 会被自动调用。 Yii正是利用这点,提供对属性的支持的。从上面的代码中,可以看出,如果访问一个对象的某个属性, Yii会调用名为 get属性名() 的函数。如, SomeObject->Foo , 会自动调用 SomeObject->getFoo() 。如果修改某一属性,会调用相应的setter函数。 如, SomeObject->Foo = $someValue ,会自动调用 SomeObject->setFoo($someValue) 。简单通俗点说,就是yii在它的yiiaseObject的基类中定义了两个魔法方法__get()和 __set(),当实例找不到属性的时候,它们定义get+属性名的一个函数来处理,就如上面的$request属性,在应用实例中是没有定义的,所以实例会执行定义的getRequest()这个公共的方法。
所以在yiiwebApplication的类中定义了一下这些方法:
通过定义这些方法就可以很好解决属性的问题,这也是yii框架的一大特点。
那么当执行getRequest()方法时,函数如下:
这个就关联到服务定位器了,类名是yiidiServiceLocator,应用实例时继承yiidiServiceLocator,所以可以直接执行$this->get()。
服务定位器yiidiServiceLocator定义了get()函数,对应的还有set函数,下面看一下get()函数:
http://www.yiichina.com/doc/guide/2.0/concept-service-locator。
当第一次通过Yii::$app->request访问时,首先执行yiidiServiceLocator的__get()函数:
函数判断是否已经创建组件实例,如果创建直接获取,如果没有,则执行父类的__get()函数,父类的__get()函数就会定义到getRequest()函数,这个函数在yiiaseApplication中定义。函数如下:
所以相对于其他的组件,也是一样的原理。如有错误,请指出!
其实yii2的核心组件主要有以下:
//日志组件 "log" => ["class" => "yiilogDispatcher"], //视图组件,这个组件代表视图文件中的$this "view" => ["class" => "yiiwebView"], //格式化组件,将一些输出按照一定的格式化显示 "formatter" => ["class" => "yiii18nFormatter"], //国际化组件,切换不同的语言版本 "i18n" => ["class" => "yiii18nI18N"], //邮件组件 "mailer" => ["class" => "yiiswiftmailerMailer"], //url美化设置组件 "urlManager" => ["class" => "yiiwebUrlManager"], //资源包管理组件 "assetManager" => ["class" => "yiiwebAssetManager"], //安全设置组件 "security" => ["class" => "yiiaseSecurity"], //请求组件 "request" => ["class" => "yiiwebRequest"], //响应请求组件 "response" => ["class" => "yiiwebResponse"], //session组件 "session" => ["class" => "yiiwebSession"], //用户组件 "user" => ["class" => "yiiwebUser"], //错误处理组件 "errorHandler" => ["class" => "yiiwebErrorHandler"], //缓存组件 "cache" => ["class" => "yii edisCache"], //数据库连接组件 "db" => ......以上这些组件可以在config.php配置,例如:
"components" => [
"request" => [
// !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
"cookieValidationKey" => "123456",
],
"cache" => [
"class" => "yii
edisCache",
"redis" => [
"hostname" => "192.168.1.19",
"port" => 6380,
"database" => 2,
]
],
"user" => [
"identityClass" => "appmodelsUser",
"enableAutoLogin" => true,
"enableSession" => true
],
"session" => [
"class" => "yii
edisSession",
"redis" => [
"hostname" => "192.168.1.19",
"port" => 6380,
"database" => 1,
],
"expire"=>50
],
"errorHandler" => [
"errorAction" => "site/error",
],
"mailer" => [
"class" => "yiiswiftmailerMailer",
// send all mails to a file by default. You have to set
// "useFileTransport" to false and configure a transport
// for the mailer to send real emails.
"useFileTransport" => true,
],
"log" => [
"traceLevel" => YII_DEBUG ? 3 : 0,
"targets" => [
[
"class" => "yiilogFileTarget",
"levels" => ["error", "warning"],
],
],
],
.........
]具体的配置要参考各个组件的配置,这里只是一个简单实例。这些核心的组件,我们可以在Yii::$app->request,或者Yii::$app->db,按照这个方式就可以获取组件的实例。那么这个过程原理是怎么样发生的呢?
大致的过程:首先在入口文件执行这一句代码
(new yiiwebApplication($config))->run();
在yiiwebApplication的类名文件中,yiiwebApplication继承yiiaseApplication,创建一个应用实例,初始化一些别名,检查配置文件,并将这一个应用实例赋值给Yii::$app这个静态变量,那么在整一个请求访问的过程中,Yii::$app就相当于应用实例存在的。
当我们执行Yii::$app->request获取请求的实例时,但由于$request的属性在这个应用实例中并没有声明的,包括在父级的基础类中也是没有的,按照正常情况,肯定是会发送错误的。因此之所以能够请求到这个属性,就要说一说yii2框架的属性了
我们知道,在读取和写入对象的一个不存在的成员变量时, __get() __set() 会被自动调用。 Yii正是利用这点,提供对属性的支持的。从上面的代码中,可以看出,如果访问一个对象的某个属性, Yii会调用名为 get属性名() 的函数。如, SomeObject->Foo , 会自动调用 SomeObject->getFoo() 。如果修改某一属性,会调用相应的setter函数。 如, SomeObject->Foo = $someValue ,会自动调用 SomeObject->setFoo($someValue) 。简单通俗点说,就是yii在它的yiiaseObject的基类中定义了两个魔法方法__get()和 __set(),当实例找不到属性的时候,它们定义get+属性名的一个函数来处理,就如上面的$request属性,在应用实例中是没有定义的,所以实例会执行定义的getRequest()这个公共的方法。
所以在yiiwebApplication的类中定义了一下这些方法:
/**
* Returns the session component.
* @return Session the session component.
*/
public function getSession()
{
return $this->get("session");
}
/**
* Returns the user component.
* @return User the user component.
*/
public function getUser()
{
return $this->get("user");
}
在yiiaseApplication的类中定义:
/**
* Returns the database connection component.
* @return yiidbConnection the database connection.
*/
public function getDb()
{
return $this->get("db");
}
/**
* Returns the log dispatcher component.
* @return yiilogDispatcher the log dispatcher application component.
*/
public function getLog()
{
return $this->get("log");
}
/**
* Returns the error handler component.
* @return yiiwebErrorHandler|yiiconsoleErrorHandler the error handler application component.
*/
public function getErrorHandler()
{
return $this->get("errorHandler");
}
/**
* Returns the cache component.
* @return yiicachingCache the cache application component. Null if the component is not enabled.
*/
public function getCache()
{
return $this->get("cache", false);
}
/**
* Returns the formatter component.
* @return yiii18nFormatter the formatter application component.
*/
public function getFormatter()
{
return $this->get("formatter");
}
/**
* Returns the request component.
* @return yiiwebRequest|yiiconsoleRequest the request component.
*/
public function getRequest()
{
return $this->get("request");
}
/**
* Returns the response component.
* @return yiiwebResponse|yiiconsoleResponse the response component.
*/
public function getResponse()
{
return $this->get("response");
}
/**
* Returns the view object.
* @return View|yiiwebView the view application component that is used to render various view files.
*/
public function getView()
{
return $this->get("view");
}
/**
* Returns the URL manager for this application.
* @return yiiwebUrlManager the URL manager for this application.
*/
public function getUrlManager()
{
return $this->get("urlManager");
}
/**
* Returns the internationalization (i18n) component
* @return yiii18nI18N the internationalization application component.
*/
public function getI18n()
{
return $this->get("i18n");
}
/**
* Returns the mailer component.
* @return yiimailMailerInterface the mailer application component.
*/
public function getMailer()
{
return $this->get("mailer");
}
/**
* Returns the auth manager for this application.
* @return yii
bacManagerInterface the auth manager application component.
* Null is returned if auth manager is not configured.
*/
public function getAuthManager()
{
return $this->get("authManager", false);
}
/**
* Returns the asset manager.
* @return yiiwebAssetManager the asset manager application component.
*/
public function getAssetManager()
{
return $this->get("assetManager");
}
/**
* Returns the security component.
* @return yiiaseSecurity the security application component.
*/
public function getSecurity()
{
return $this->get("security");
}
通过定义这些方法就可以很好解决属性的问题,这也是yii框架的一大特点。
那么当执行getRequest()方法时,函数如下:
public function getRequest()
{
return $this->get("request");
}这时执行$this->get("request"),那么get方法又是怎么来的呢?这个就关联到服务定位器了,类名是yiidiServiceLocator,应用实例时继承yiidiServiceLocator,所以可以直接执行$this->get()。
服务定位器yiidiServiceLocator定义了get()函数,对应的还有set函数,下面看一下get()函数:
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;
}
}id就是在配置文件中定义的组件的名称,get()方法就是要获取一个组件,实现实例化,并保存在私有的_components数组变量中。具体了解一下http://www.yiichina.com/doc/guide/2.0/concept-service-locator。
当第一次通过Yii::$app->request访问时,首先执行yiidiServiceLocator的__get()函数:
public function __get($name)
{
if ($this->has($name)) {
return $this->get($name);
} else {
return parent::__get($name);
}
}函数判断是否已经创建组件实例,如果创建直接获取,如果没有,则执行父类的__get()函数,父类的__get()函数就会定义到getRequest()函数,这个函数在yiiaseApplication中定义。函数如下:
public function getRequest()
{
return $this->get("request");
}
这时,会执行在yiidiServiceLocator定义的get()函数,创建实例对象,并保存在变量中,在同一个应用内,下次在访问同一个组件时,直接可以获取访问,不需要再创建实例。所以相对于其他的组件,也是一样的原理。如有错误,请指出!
声明:该文观点仅代表作者本人,入门客AI创业平台信息发布平台仅提供信息存储空间服务,如有疑问请联系rumenke@qq.com。
- 上一篇: yii2框架-restful的基础入门(二十一)
- 下一篇: swoole-swoole是什么能做什么
