程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> yii源碼分析2,yii源碼分析

yii源碼分析2,yii源碼分析

編輯:關於PHP編程

yii源碼分析2,yii源碼分析


轉載請注明:TheViper http://www.cnblogs.com/TheViper/

上一篇主要分析了Yii::createWebApplication ( $config )->run ();的createWebApplication ( $config )部分,這篇分析後面的。

 run()也是不在CWebApplication裡面,在CApplication 裡。

 1 <?php
 2 abstract class CApplication extends CModule {
 3     private $_id;
 4     private $_basePath;
 5     abstract public function processRequest();
 6     public function __construct($config = null) {
 7         if (is_string ( $config ))
 8             $config = require ($config);
 9         Yii::setApplication ( $this );//保存整個app實例
10         if (isset ( $config ['basePath'] )) {
11             $this->setBasePath ( $config ['basePath'] );
12             unset ( $config ['basePath'] );
13         } else
14             $this->setBasePath ( 'protected' );
15         //設置別名,後面就可以用application表示basePath了
16         Yii::setPathOfAlias ( 'application', $this->getBasePath () );
17         //鉤子,模塊 預 初始化時執行,子類實現。不過這時,配置還沒有寫入框架
18         $this->preinit ();
19         $this->registerCoreComponents ();
20         //父類實現
21         $this->configure ( $config );
22         //加載靜態應用組件
23         $this->preloadComponents ();
24         //這才開始初始化模塊
25         $this->init ();
26     }
27     protected function registerCoreComponents() {
28         $components = array (
29                 'request' => array (
30                         'class' => 'CHttpRequest'
31                 ),
32                 'urlManager' => array (
33                         'class' => 'CUrlManager'
34                 )
35         );
36 
37         $this->setComponents ( $components );//父類實現
38     }
39     public function run() {
40         $this->processRequest ();
41     }
42     public function getId() {
43         if ($this->_id !== null)
44             return $this->_id;
45         else
46             return $this->_id = sprintf ( '%x', crc32 ( $this->getBasePath () . $this->name ) );
47     }
48     public function setId($id) {
49         $this->_id = $id;
50     }
51     public function getBasePath() {
52         return $this->_basePath;
53     }
54     public function setBasePath($path) {
55         if (($this->_basePath = realpath ( $path )) === false || ! is_dir ( $this->_basePath ))
56             return;
57     }
58     public function getDb() {
59         return $this->getComponent ( 'db' );//父類實現
60     }
61     public function getUrlManager() {
62         return $this->getComponent ( 'urlManager' );
63     }
64     public function getController() {
65         return null;
66     }
67     public function getBaseUrl($absolute = false) {
68         return $this->getRequest ()->getBaseUrl ( $absolute );
69     }
70 }

run()又用了CWebApplication裡面的processRequest()。薛強大哥(yii作者),架構要不要這樣啊.裁剪後當然覺得這樣的調用很沒意思。

後面的主要在CWebApplication裡了。

 1 <?php
 2 class CWebApplication extends CApplication {
 3     public $controllerNamespace;
 4     private $_controllerPath;
 5     private $_viewPath;
 6     private $_systemViewPath;
 7     private $_controller;
 8     public $controllerMap=array();
 9     public function processRequest() {//開始執行請求
10         //獲取urlManager組件,解析請求,得到controller/action這種格式的string,
11         //並且將隱藏參數與請求的參數一一對應,匹配起來,寫入$_REQUEST中
12         $route = $this->getUrlManager ()->parseUrl ($this->getRequest());
13         $this->runController ( $route );
14     }
15     public function getRequest() {//獲取request組件
16         return $this->getComponent ( 'request' );
17     }
18     protected function registerCoreComponents() {//注冊核心組件
19         parent::registerCoreComponents ();
20     }
21     //執行contronller
22     public function runController($route) {
23         if (($ca = $this->createController ( $route )) !== null) {
24             list ( $controller, $actionID ) = $ca;
25             $oldController = $this->_controller;
26             $this->_controller = $controller;
27             $controller->init ();//鉤子,在執行action方法前調用,子類去實現
28             $controller->run ( $actionID );//開始轉入controller類中action方法的執行
29             $this->_controller = $oldController;
30         }
31     }
32     //創建controller類實例,從controller/action這種格式的string中解析出$controller, $actionID 
33     public function createController($route, $owner = null) {
34         if ($owner === null)
35             $owner = $this;
36         if (($route = trim ( $route, '/' )) === '')
37             $route = $owner->defaultController;
38 
39         $route .= '/';
40         while ( ($pos = strpos ( $route, '/' )) !== false ) {
41             $id = substr ( $route, 0, $pos );
42             if (! preg_match ( '/^\w+$/', $id ))
43                 return null;
44             $id = strtolower ( $id );
45             $route = ( string ) substr ( $route, $pos + 1 );
46             if (! isset ( $basePath ))             // first segment
47             {
48                 $basePath = $owner->getControllerPath ();
49                 $controllerID = '';
50             } else {
51                 $controllerID .= '/';
52             }
53             $className = ucfirst ( $id ) . 'Controller';
54             $classFile = $basePath . DIRECTORY_SEPARATOR . $className . '.php';
55 
56             if (is_file ( $classFile )) {
57                 if (! class_exists ( $className, false ))
58                     require ($classFile);
59                 if (class_exists ( $className, false ) && is_subclass_of ( $className, 'CController' )) {
60                     $id [0] = strtolower ( $id [0] );
61                     return array (
62                             new $className ( $controllerID . $id, $owner === $this ? null : $owner ),
63                             $this->parseActionParams ( $route )
64                     );
65                 }
66                 return null;
67             }
68             $controllerID .= $id;
69             $basePath .= DIRECTORY_SEPARATOR . $id;
70         }
71     }
72     protected function parseActionParams($pathInfo) {
73         if (($pos = strpos ( $pathInfo, '/' )) !== false) {
74             $manager = $this->getUrlManager ();//再次獲取urlManager,在上面第一次調用中已經導入。
75             $manager->parsePathInfo ( ( string ) substr ( $pathInfo, $pos + 1 ) );
76             $actionID = substr ( $pathInfo, 0, $pos );
77             return $manager->caseSensitive ? $actionID : strtolower ( $actionID );
78         } else
79             return $pathInfo;
80     }
81     public function getControllerPath() {
82         if ($this->_controllerPath !== null)
83             return $this->_controllerPath;
84         else
85             return $this->_controllerPath = $this->getBasePath () . DIRECTORY_SEPARATOR . 'controllers';
86     }
87     //兩個鉤子,子類去實現
88     public function beforeControllerAction($controller, $action) {
89         return true;
90     }
91     public function afterControllerAction($controller, $action) {
92     }
93     protected function init() {
94         parent::init ();
95     }
96 }

對於$this->getUrlManager (),YiiBase裡面有'CUrlManager' => 'CUrlManager.php'這個映射,說明是實例化了CUrlManager這個類。

 

 1 <?php
 2 class CUrlManager {
 3     const GET_FORMAT = 'get';
 4     public $rules = array ();
 5     public $urlSuffix = '';
 6     public $caseSensitive = true;
 7     public $urlRuleClass = 'CUrlRule';
 8     private $_urlFormat = self::GET_FORMAT;
 9     private $_rules = array ();
10     private $_baseUrl;
11     protected function processRules() {
12         //遍歷自定義的請求匹配規則
13         foreach ( $this->rules as $pattern => $route ) {
14             //對每一個規則創建CUrlRule實例
15             $this->_rules [] = $this->createUrlRule ( $route, $pattern );
16         }
17     }
18     protected function createUrlRule($route, $pattern) {
19         if (is_array ( $route ) && isset ( $route ['class'] ))
20             return $route;
21         else {
22             //import第二個參數表示是否立即包含類文件。 如果為flase,則類文件僅在被使用時包含。 這個參數僅當使用一個類的路徑 別名 時才會用到
23             $urlRuleClass = Yii::import ( $this->urlRuleClass, true );
24             //創建CUrlRule實例
25             return new $urlRuleClass ( $route, $pattern );
26         }
27     }
28     //類似於__construct()
29     public function init() {
30         $this->processRules ();
31     }
32     public function parseUrl($request) {
33         //獲取請求
34         $rawPathInfo = $request->getPathInfo ();
35         $pathInfo = $this->removeUrlSuffix ( $rawPathInfo, $this->urlSuffix );
36         foreach ( $this->_rules as $i => $rule ) {
37             if (($r = $rule->parseUrl ( $this, $pathInfo, $rawPathInfo )) !== false) {
38                 return $r;
39             }
40         }
41         return $pathInfo;
42     }
43     //解析請求,將請求參數寫入$_REQUEST
44     public function parsePathInfo($pathInfo) {
45         if ($pathInfo === '')
46             return;
47         $segs = explode ( '/', $pathInfo . '/' );
48         $n = count ( $segs );
49         for($i = 0; $i < $n - 1; $i += 2) {
50             $key = $segs [$i];
51             if ($key === '')
52                 continue;
53             $value = $segs [$i + 1];
54             if (($pos = strpos ( $key, '[' )) !== false && ($m = preg_match_all ( '/\[(.*?)\]/', $key, $matches )) > 0) {
55                 $name = substr ( $key, 0, $pos );
56                 for($j = $m - 1; $j >= 0; -- $j) {
57                     if ($matches [1] [$j] === '')
58                         $value = array (
59                             $value 
60                             );
61                     else
62                         $value = array (
63                             $matches [1] [$j] => $value 
64                             );
65                 }
66                 if (isset ( $_GET [$name] ) && is_array ( $_GET [$name] ))
67                     $value = CMap::mergeArray ( $_GET [$name], $value );
68                 $_REQUEST [$name] = $_GET [$name] = $value;
69             } else {                
70                 $_REQUEST [$key] = $_GET [$key] = $value;
71             }
72         }
73     }
74     //去除請求後綴,如video/broadcast.html=>video/broadcast 
75     public function removeUrlSuffix($pathInfo, $urlSuffix) {
76         if ($urlSuffix !== '' && substr ( $pathInfo, - strlen ( $urlSuffix ) ) === $urlSuffix)
77             return substr ( $pathInfo, 0, - strlen ( $urlSuffix ) );
78         else
79             return $pathInfo;
80     }
81 }

yii在創建組件的時候,在調用了CModule的getComponent($id, $createIfNull = true)裡面調用了$component->init ();。

所以這裡進入init(),然後processRules()遍歷自定義的請求匹配規則。如

 1                 'urlManager' => array (
 2                         'urlFormat' => 'path',
 3                         'rules' => array (
 4                                 'comment_reply/<a:\d+>/<ci:\d+>' => 'reply/load_comment_reply',
 5                                 'b/<id:\d+>' => array (
 6                                         'video/broadcast',
 7                                         'urlSuffix' => '.html' 
 8                                 ),
 9                                 'c/<list_start:\d+>' => 'video/list_more_video',
10                                 'u/reg' => 'user/reg',
11                                 'v/upload' => 'video/upload_video',
12                                 'login' => 'user/to_login',
13                                 'show_chanel/<chanel_id:\d+>' => 'show/chanel' ,
14                                 'show/<show_id:\d+>' => 'show/show',
15                         ) 
16                 ) 

 $this->_rules [] = $this->createUrlRule ( $route, $pattern );對每一個規則創建CUrlRule實例,並保存。

 1 <?php
 2 class CUrlRule {
 3     public $urlSuffix;
 4     public $defaultParams = array ();
 5     public $route;
 6     public $routePattern;
 7     public $pattern;
 8     public $template;
 9     public $params = array ();
10     //根據自定義規則構建匹配參數的正則表達式。
11     public function __construct($route, $pattern) {
12         if (is_array ( $route )) {
13             foreach ( array (
14                     'urlSuffix',
15                     'caseSensitive',
16                     'defaultParams',
17             ) as $name ) {
18                 if (isset ( $route [$name] ))
19                     $this->$name = $route [$name];
20             }
21             if (isset ( $route ['pattern'] ))
22                 $pattern = $route ['pattern'];
23             $route = $route [0];
24         }
25         $this->route = trim ( $route, '/' );
26         
27         $tr2 ['/'] = $tr ['/'] = '\\/';
28         $tr ['.'] = '\\.';
29         
30         $this->hasHostInfo = ! strncasecmp ( $pattern, 'http://', 7 ) || ! strncasecmp ( $pattern, 'https://', 8 );
31         
32         if (preg_match_all ( '/<(\w+):?(.*?)?>/', $pattern, $matches )) {
33             $tokens = array_combine ( $matches [1], $matches [2] );
34             foreach ( $tokens as $name => $value ) {
35                 if ($value === '')
36                     $value = '[^\/]+';
37                 $tr ["<$name>"] = "(?P<$name>$value)";
38                 //取出自定義規則中隱藏的參數,保存
39                 if (isset ( $this->references [$name] ))
40                     $tr2 ["<$name>"] = $tr ["<$name>"];
41                 else
42                     $this->params [$name] = $value;
43             }
44         }
45         $p = rtrim ( $pattern, '*' );
46         $this->append = $p !== $pattern;
47         $p = trim ( $p, '/' );
48         $this->template = preg_replace ( '/<(\w+):?.*?>/', '<$1>', $p );
49         $this->pattern = '/^' . strtr ( $this->template, $tr ) . '\/';
50         //合成匹配的正則表達式
51         if ($this->append)
52             $this->pattern .= '/u';
53         else
54             $this->pattern .= '$/u';
55     }
56     //根據正則表達式和請求,將隱藏參數與請求參數一一匹配,保存$_REQUEST
57     public function parseUrl($manager, $pathInfo, $rawPathInfo) {
58         if ($this->urlSuffix !== null) {
59             $pathInfo = $manager->removeUrlSuffix ( $rawPathInfo, $this->urlSuffix );
60         }
61         $pathInfo .= '/';
62         if (preg_match ( $this->pattern, $pathInfo, $matches )) {
63             foreach ( $this->defaultParams as $name => $value ) {
64                 if (! isset ( $_GET [$name] ))
65                     $_REQUEST [$name] = $_GET [$name] = $value;
66             }
67             $tr = array ();
68             foreach ( $matches as $key => $value ) {
69                 if (isset ( $this->references [$key] ))
70                     $tr [$this->references [$key]] = $value;
71                 elseif (isset ( $this->params [$key] ))
72                     $_REQUEST [$key] = $_GET [$key] = $value;
73             }
74             if ($pathInfo !== $matches [0]) //如果還有另外的請求參數
75                 $manager->parsePathInfo ( ltrim ( substr ( $pathInfo, strlen ( $matches [0] ) ), '/' ) );
76             return $this->route;
77         } else
78             return false;
79     }
80 }

CUrlRule中的parseUrl($manager, $pathInfo, $rawPathInfo)這裡暫時還沒用到。

然後回到CWebApplication中的¥route=$this->getUrlManager ()->parseUrl ($this->getRequest());。後面parseUrl開始解析請求了。

轉到CUrlManager的parseUrl($request),遍歷創建CUrlRule過程中保存的匹配規則,再在CUrlRule裡面用CUrlRule的parseUrl($manager, $pathInfo, $rawPathInfo)將隱藏參數與請求參數一一匹配,保存$_REQUEST.

比如:

'b/<id:\d+>' => array (
  'video/broadcast',
  'urlSuffix' => '.html'
)

我的請求是b/1.html,就會被解析成video/broadcast?id=1.而最終的$route就是這個。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved