zoukankan      html  css  js  c++  java
  • yii源码分析2

    转载请注明: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就是这个。

    最后附上,裁剪的yii http://files.cnblogs.com/TheViper/framework.zip

    下一篇

     

  • 相关阅读:
    自定义的弹出框列表适配器,类似于大众点评或美团
    Android 微信支付&支付宝支付
    动态设置 view 在布局中位置
    android 之图片异步加载
    android 侧滑菜单
    Google 官方 侧滑 drawerlayout
    python D27网络传输协议
    计算机单位换算、以及sort、sorted函数的区别
    python D26 socket、网络整个通信流程
    python D25 包
  • 原文地址:https://www.cnblogs.com/TheViper/p/4089188.html
Copyright © 2011-2022 走看看