["class" " />
入门客AI创业平台(我带你入门,你带我飞行)
博文笔记

yii2框架-yii2的组件和服务定位器(四)

创建时间:2016-05-24 投稿人: 浏览次数:2824
上一节主要是分析了yii2的自动加载函数,下面在分析一下yii2的核心组件与服务定位器。

其实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。