yii源码分析2,yii源码分析转载请注明:theviper http://www.cnblogs.com/theviper/
上一篇主要分析了yii::createwebapplication ( $config )->run ();的createwebapplication ( $config )部分,这篇分析后面的。
run()也是不在cwebapplication里面,在capplication 里。
1 setbasepath ( $config ['basepath'] );12 unset ( $config ['basepath'] );13 } else14 $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 else46 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 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 //执行contronller22 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 segment47 {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 } else79 return $pathinfo;80 }81 public function getcontrollerpath() {82 if ($this->_controllerpath !== null)83 return $this->_controllerpath;84 else85 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 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 //解析请求,将请求参数写入$_request44 public function parsepathinfo($pathinfo) {45 if ($pathinfo === '')46 return;47 $segs = explode ( '/', $pathinfo . '/' );48 $n = count ( $segs );49 for($i = 0; $i 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 else62 $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 else79 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//' => 'reply/load_comment_reply', 5 'b/' => array ( 6 'video/broadcast', 7 'urlsuffix' => '.html' 8 ), 9 'c/' => 'video/list_more_video',10 'u/reg' => 'user/reg',11 'v/upload' => 'video/upload_video',12 'login' => 'user/to_login',13 'show_chanel/' => 'show/chanel' ,14 'show/' => 'show/show',15 ) 16 )
$this->_rules [] = $this->createurlrule ( $route, $pattern );对每一个规则创建curlrule实例,并保存。
1 $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 ( '//', $pattern, $matches )) {33 $tokens = array_combine ( $matches [1], $matches [2] );34 foreach ( $tokens as $name => $value ) {35 if ($value === '')36 $value = '[^\/]+';37 $tr [] = (?p$value);38 //取出自定义规则中隐藏的参数,保存39 if (isset ( $this->references [$name] ))40 $tr2 [] = $tr [];41 else42 $this->params [$name] = $value;43 }44 }45 $p = rtrim ( $pattern, '*' );46 $this->append = $p !== $pattern;47 $p = trim ( $p, '/' );48 $this->template = preg_replace ( '//', '', $p );49 $this->pattern = '/^' . strtr ( $this->template, $tr ) . '\/';50 //合成匹配的正则表达式51 if ($this->append)52 $this->pattern .= '/u';53 else54 $this->pattern .= '$/u';55 }56 //根据正则表达式和请求,将隐藏参数与请求参数一一匹配,保存$_request57 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 } else78 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/' => array (
'video/broadcast',
'urlsuffix' => '.html'
)
我的请求是b/1.html,就会被解析成video/broadcast?id=1.而最终的$route就是这个。
http://www.bkjia.com/phpjc/909081.htmlwww.bkjia.comtruehttp://www.bkjia.com/phpjc/909081.htmltecharticleyii源码分析2,yii源码分析 转载请注明:theviperhttp://www.cnblogs.com/theviper/ 上一篇主要分析了yii::createwebapplication ( $config )-run ();的createwebappli...
