摘要:行為是如何注冊到組件的呢通過注冊行為之后,實際上是添加到了的屬性中那么行為中的屬性,就添加到了,中進行直接調(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
摘要:高性能始終是的首要目標之一。版是上代的老版本,現(xiàn)在處于維護狀態(tài)。版是一個完全重寫的版本,采用了最新的技術(shù)和協(xié)議,包括依賴包管理器代碼規(guī)范命名空間特質(zhì)等等。所以,我們學習版本。啟用本鏡像服務(wù)系統(tǒng)全局配置即將配置信息添加到的全局配置文件中。 工作中需要用到Y(jié)II框架,于是乎,系統(tǒng)的學習下這套框架,詳細教程請看考該站完整系列:YII2教程 一、YII簡介 1、什么是YII Yii 是一個高性...
摘要:據(jù)官方介紹,框架廣泛的使用了一種叫做延遲加載的技術(shù),從而達到這樣的效果。比如我們在判斷中,需要實例化類的時候,再去加載相應(yīng)的文件。代碼如下等于不等于優(yōu)化過后的文件效率肯定得到了提升,這個也就是類的延遲加載雛形。這就是的延遲加載了。 Yii框架號稱最高效的PHP框架,執(zhí)行效率高出其他框架很多。據(jù)官方介紹,Yii框架廣泛的使用了一種叫做延遲加載的技術(shù),從而達到這樣的效果。 下面我們就通過實...
摘要:今天我就來講講插件的使用,它是如何實現(xiàn)列表表頭自定義顯示字段的,我把我的經(jīng)驗分享出來,滿足一下不懂英語的人,給你們搭個快車。需求分析實現(xiàn)列表表頭自定義顯示字段,自定義表頭排序。 序言 Yii2框架的擴展性能真的很不錯,很多效果都可以通過插件去實現(xiàn),你想不到的老外都幫你想好了,于是,人群中就流傳了這么一句話:效果不會寫不要緊,會用插件也不錯。GitHub是一個龐大而且開放的資源庫,平時有...
摘要:在用戶注冊的時候是為空的,當用戶忘記密碼在登錄頁面點擊后生成的,用來給用法發(fā)送郵件后重置密碼時進行驗證。如有錯誤,不吝賜教。 注冊 在advanced模板中,進入frontend/index.php?r=site%2Fsignup頁面,可以看到框架的注冊頁面showImg(https://segmentfault.com/img/bVDEaZ?w=300&h=235); 填寫完User...
摘要:運行來安裝指定的擴展。這更便于用戶辨別是否是的擴展。當用戶運行安裝一個擴展時,文件會被自動更新使之包含新擴展的信息。上述代碼表明該擴展依賴于包。例如,上述的條目聲明將對應(yīng)于別名。為達到這個目的,你應(yīng)當在公開發(fā)布前做測試。 簡述 擴展是專門設(shè)計的在 Yii 應(yīng)用中隨時可拿來使用的, 并可重發(fā)布的軟件包。 基礎(chǔ) 例如, yiisoft/yii2-debug 擴展在你的應(yīng)用的每個頁面底部添加...
閱讀 1564·2023-04-26 02:29
閱讀 3041·2021-10-11 10:58
閱讀 2897·2021-10-08 10:16
閱讀 3156·2021-09-24 09:47
閱讀 1568·2019-08-29 16:56
閱讀 2716·2019-08-29 11:03
閱讀 1998·2019-08-26 13:35
閱讀 3172·2019-08-26 13:34