国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Yii2 完整框架分析(詳細)

spademan / 1735人閱讀

摘要:行為是如何注冊到組件的呢通過注冊行為之后,實際上是添加到了的屬性中那么行為中的屬性,就添加到了,中進行直接調(diào)用行為里面的方法的時候,實際上觸發(fā)了里面的魔術(shù)方法繼承鏈圖解

Yii2 框架Trace 準備

了解composer的autoload psr0 psr4 加載機制

了解spl_autoload_register

了解依賴注入的實現(xiàn)原理反射

了解常用魔術(shù)方法__set,__get,__call

熱情與專注

入口分析

加載composer 的自動加載器,支持了PSR-0 PSR-4

require(__DIR__ . "/../vendor/autoload.php");

進行常量的定義,并且聲明了最基本的方法例如getVersion

require __DIR__ . "/BaseYii.php";

加載Yii自己的autoload加載器,從classmap中尋找,指定的類,如果沒有找到,會解析名稱到路徑。

spl_autoload_register(["Yii", "autoload"], true, true);
Yii::$classMap = require __DIR__ . "/classes.php";

todo 容器生成

Yii::$container = new yiidiContainer();

開始生成一個應(yīng)用主體,并且加載了config配置,直接運行

(new yiiwebApplication($config))->run();
主體生成

application is the base class for all web application classes.

Yii::$app 是應(yīng)用主體的實例,一個請求只會生成一個應(yīng)用主體
Application類中,定義了初始的defaultRoute,以及coreComponent核心組件的列表,還有一些請求和相應(yīng)相關(guān)的方法

繼承鏈

web/application=>base/application=>base/Model=>id/ServiceLocator=>base/component=>base/object=>base/configurable

初始化主體的配置
public function __construct($config = [])
    {
        Yii::$app = $this; // 這樣在任何地方都可以通過靜態(tài)方法的方式,來調(diào)用應(yīng)用主體
        static::setInstance($this); // 將請求過來的的類實力,進行保存

        $this->state = self::STATE_BEGIN;

        $this->preInit($config); // 進行config的初始化,給路徑起別名,設(shè)置時區(qū)等,并且最后加載了核心組件

        $this->registerErrorHandler($config); // 注冊錯誤句柄,用來捕捉和處理錯誤的方法

        Component::__construct($config); // 
    }

其中preInit會進行一個注冊核心組件,這里web的入口進行了擴展,包含了request等

public function coreComponents()
    {
        return array_merge(parent::coreComponents(), [
            "request" => ["class" => "yiiwebRequest"],
            "response" => ["class" => "yiiwebResponse"],
            "session" => ["class" => "yiiwebSession"],
            "user" => ["class" => "yiiwebUser"],
            "errorHandler" => ["class" => "yiiwebErrorHandler"],
        ]);
    }

講configure格式為對象,存儲到應(yīng)用主體中

public function __construct($config = [])
    {
        if (!empty($config)) {
            Yii::configure($this, $config);
        }
        $this->init();
    }
組件注冊

這里我們來看下組件是如何注冊到應(yīng)用主體中的,這個-> 實際上調(diào)用的是__Set魔術(shù)方法,
那我們再看這個$this是什么,很明顯是指yiiwebapplication

public static function configure($object, $properties)
    {
        foreach ($properties as $name => $value) {
            $object->$name = $value;
        }

        return $object;
    }

我們從webapplication向parent一層一層的找,找到了__set 的定義,在basecomponent

public function __set($name, $value)
    {
        $setter = "set" . $name;
        if (method_exists($this, $setter)) {
            // set property
            $this->$setter($value);

            return;
        } elseif (strncmp($name, "on ", 3) === 0) {
            // on event: attach event handler
            $this->on(trim(substr($name, 3)), $value);

            return;
        } elseif (strncmp($name, "as ", 3) === 0) {
            // as behavior: attach behavior
            $name = trim(substr($name, 3));
            $this->attachBehavior($name, $value instanceof Behavior ? $value : Yii::createObject($value));

            return;
        }

        // behavior property
        $this->ensureBehaviors();
        foreach ($this->_behaviors as $behavior) {
            if ($behavior->canSetProperty($name)) {
                $behavior->$name = $value;
                return;
            }
        }

        if (method_exists($this, "get" . $name)) {
            throw new InvalidCallException("Setting read-only property: " . get_class($this) . "::" . $name);
        }

        throw new UnknownPropertyException("Setting unknown property: " . get_class($this) . "::" . $name);
    }

上面的set方法,會遍歷config的屬性,來交給不同的set方法處理,果然恰好存在了一個setComponents,用來處理組件

public function setComponents($components)
    {
        foreach ($components as $id => $component) {
            $this->set($id, $component);
        }
    }

最終組件配置就這樣被注冊到了$this->_definitions里面,后面我們可以通過$this->get($id) 來獲取組件配置

public function set($id, $definition)
    { 
        unset($this->_components[$id]);

        if ($definition === null) {
            unset($this->_definitions[$id]);
            return;
        }

        if (is_object($definition) || is_callable($definition, true)) {
            // an object, a class name, or a PHP callable
            $this->_definitions[$id] = $definition;
        } elseif (is_array($definition)) {
            // a configuration array
            if (isset($definition["class"])) {
                $this->_definitions[$id] = $definition;
            } else {
                throw new InvalidConfigException("The configuration for the "$id" component must contain a "class" element.");
            }
        } else {
            throw new InvalidConfigException("Unexpected configuration type for the "$id" component: " . gettype($definition));
        }

    }

注意這個init,并不是當前類下面的init方法,而是被webapplication 覆蓋

public function init()
    {
        $this->state = self::STATE_INIT;
        $this->bootstrap();
    }

同樣bootstrap方法也被覆蓋

protected function bootstrap()
    {
        $request = $this->getRequest();
        Yii::setAlias("@webroot", dirname($request->getScriptFile()));
        Yii::setAlias("@web", $request->getBaseUrl());

        parent::bootstrap();
    }

看下getRequest是怎么回事,跟蹤代碼,它通過get方法,來從_definitions中獲取request對應(yīng)的配置
然后根據(jù)配置中的yiiwebrequest 來進行創(chuàng)建對象,其中$type 就是配置

public static function createObject($type, array $params = [])
    {
        if (is_string($type)) {
            return static::$container->get($type, $params);
        } elseif (is_array($type) && isset($type["class"])) {
            $class = $type["class"];
            unset($type["class"]);
            return static::$container->get($class, $params, $type); // request 走的是這里
        } elseif (is_callable($type, true)) {
            return static::$container->invoke($type, $params);
        } elseif (is_array($type)) {
            throw new InvalidConfigException("Object configuration must be an array containing a "class" element.");
        }

        throw new InvalidConfigException("Unsupported configuration type: " . gettype($type));
    }
    

進行完web層的引導(dǎo)之后,繼續(xù)進行base層的引導(dǎo),包括對配置中bootstrap的引導(dǎo)注冊,會直接通過容器得到實例。(具體不詳)

小結(jié)

在上面的new的過程中,完成了組件的注冊,配置的初始化,并且學到了get是createObject通過依賴注入的方法,獲取組件對象

請求的處理

前面所有的配置和準備都初始化完畢之后,要進行請求處理了。

這一句的run方法,就是處理請求的整個啟動入口

$application->run();

使用handleRequest方法來處理請求,并且參數(shù)是request實例,其中handleRequest方法要看webapplication層的封裝

$response = $this->handleRequest($this->getRequest());
調(diào)用resolve進行解析
list($route, $params) = $request->resolve();

我們再看Urlmanager的時候,發(fā)現(xiàn)里面定義的routeParam是r也就是默認接受參數(shù)的值(重要)
實際上下面這段代碼完成的就是解析了$_GET的值,從里面尋找routeParam 定義的值(r)所代表的內(nèi)容

$result = Yii::$app->getUrlManager()->parseRequest($this);

這里要調(diào)用action方法了

$this->requestedRoute = $route;
$result = $this->runAction($route, $params);
創(chuàng)建控制器+調(diào)用action

實際上runAction中的主要內(nèi)容就是createController的實現(xiàn):

// parts 分為兩部分,0 是controller的實例,1 是實例里面的方法名稱
$parts = $this->createController($route);
...
...

/* @var $controller Controller */ // 這是一個跟蹤優(yōu)化,不然controller->runaction 就定位不了了
list($controller, $actionID) = $parts;
$oldController = Yii::$app->controller;
Yii::$app->controller = $controller;
$result = $controller->runAction($actionID, $params);

如果遇到了控制器,那么直接返回控制器對象和方法route的名稱,這里route類似于action方法名稱,代碼略微繁瑣,但是很清晰,具體實現(xiàn)就是

路由解析規(guī)則

例如r=site

尋找controller,找到site控制器,直接實例化

例如r=site/index

構(gòu)造控制器,并且id為site、route為index

例如r=site/index/test

發(fā)現(xiàn)沒有找到控制器,那么從模塊中獲取,這里是重新構(gòu)造id為site/index route為test,然后調(diào)用createControllerById 方法來獲取控制器(具體不詳,不過應(yīng)該是通過namespace定位了)

而且createController直接返回了controller的實例

然后我們在createAction中找到解析action方法名稱的代碼
例如r=site/index-test 那么下面對應(yīng)的methodName就是actionIndexTest

$methodName = "action" . str_replace(" ", "", ucwords(implode(" ", explode("-", $id))));
內(nèi)容輸出

將調(diào)用action方法的值,進行返回,然后直接交給yiiwebResponse作為data屬性的一部分。最后調(diào)用send方法,進行輸出。

public function send()
    {
        if ($this->isSent) {
            return;
        }
        $this->trigger(self::EVENT_BEFORE_SEND);
        $this->prepare();
        $this->trigger(self::EVENT_AFTER_PREPARE);
        $this->sendHeaders();
        $this->sendContent();
        $this->trigger(self::EVENT_AFTER_SEND);
        $this->isSent = true;
    }
行為是如何注冊到組件的呢?

通過attacheBehavior注冊行為之后,實際上是添加到了$this_behaviors屬性中

那么行為中的屬性,就添加到了,_behaviors

進行直接調(diào)用行為里面的方法的時候,實際上觸發(fā)了yiiaseComponent里面的__call魔術(shù)方法

繼承鏈圖解

END

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/26127.html

相關(guān)文章

  • YII2快速學習筆記

    摘要:高性能始終是的首要目標之一。版是上代的老版本,現(xiàn)在處于維護狀態(tài)。版是一個完全重寫的版本,采用了最新的技術(shù)和協(xié)議,包括依賴包管理器代碼規(guī)范命名空間特質(zhì)等等。所以,我們學習版本。啟用本鏡像服務(wù)系統(tǒng)全局配置即將配置信息添加到的全局配置文件中。 工作中需要用到Y(jié)II框架,于是乎,系統(tǒng)的學習下這套框架,詳細教程請看考該站完整系列:YII2教程 一、YII簡介 1、什么是YII Yii 是一個高性...

    kbyyd24 評論0 收藏0
  • Yii2性能優(yōu)化之:類的延遲加載技術(shù)介紹

    摘要:據(jù)官方介紹,框架廣泛的使用了一種叫做延遲加載的技術(shù),從而達到這樣的效果。比如我們在判斷中,需要實例化類的時候,再去加載相應(yīng)的文件。代碼如下等于不等于優(yōu)化過后的文件效率肯定得到了提升,這個也就是類的延遲加載雛形。這就是的延遲加載了。 Yii框架號稱最高效的PHP框架,執(zhí)行效率高出其他框架很多。據(jù)官方介紹,Yii框架廣泛的使用了一種叫做延遲加載的技術(shù),從而達到這樣的效果。 下面我們就通過實...

    tuniutech 評論0 收藏0
  • 列表——表頭自定義顯示字段

    摘要:今天我就來講講插件的使用,它是如何實現(xiàn)列表表頭自定義顯示字段的,我把我的經(jīng)驗分享出來,滿足一下不懂英語的人,給你們搭個快車。需求分析實現(xiàn)列表表頭自定義顯示字段,自定義表頭排序。 序言 Yii2框架的擴展性能真的很不錯,很多效果都可以通過插件去實現(xiàn),你想不到的老外都幫你想好了,于是,人群中就流傳了這么一句話:效果不會寫不要緊,會用插件也不錯。GitHub是一個龐大而且開放的資源庫,平時有...

    Yangyang 評論0 收藏0
  • Yii2框架源碼分析之如何實現(xiàn)注冊和登錄

    摘要:在用戶注冊的時候是為空的,當用戶忘記密碼在登錄頁面點擊后生成的,用來給用法發(fā)送郵件后重置密碼時進行驗證。如有錯誤,不吝賜教。 注冊 在advanced模板中,進入frontend/index.php?r=site%2Fsignup頁面,可以看到框架的注冊頁面showImg(https://segmentfault.com/img/bVDEaZ?w=300&h=235); 填寫完User...

    chemzqm 評論0 收藏0
  • Yii修行之路 - Extension 擴展

    摘要:運行來安裝指定的擴展。這更便于用戶辨別是否是的擴展。當用戶運行安裝一個擴展時,文件會被自動更新使之包含新擴展的信息。上述代碼表明該擴展依賴于包。例如,上述的條目聲明將對應(yīng)于別名。為達到這個目的,你應(yīng)當在公開發(fā)布前做測試。 簡述 擴展是專門設(shè)計的在 Yii 應(yīng)用中隨時可拿來使用的, 并可重發(fā)布的軟件包。 基礎(chǔ) 例如, yiisoft/yii2-debug 擴展在你的應(yīng)用的每個頁面底部添加...

    bovenson 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<