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是什么能做什么