Yii分析1:web程序入口(3)
程序员文章站
2022-03-02 11:40:54
...
本文分析前两篇文章用到的一些函数。
上一篇提到在preloadComponents的时候会调用getComponent,我们来看一下getComponent的细节:
Yii_PATH/base/CModule.php
//第二个参数标识如果是空则创建之,默认为true public function getComponent($id,$createIfNull=true) { if(isset($this->_components[$id])) return $this->_components[$id]; //_componentConfig是在configure方法中由setComponents中已经保存的变量 else if(isset($this->_componentConfig[$id]) && $createIfNull) { $config=$this->_componentConfig[$id]; unset($this->_componentConfig[$id]); //如果没有设置enable参数或者enable参数为true if(!isset($config['enabled']) || $config['enabled']) { Yii::trace("Loading \"$id\" application component",'system.web.CModule'); unset($config['enabled']); //创建组件,并完成初始化 $component=Yii::createComponent($config); $component->init(); return $this->_components[$id]=$component; } } }
下面是Yii::createComponent的实现:
public static function createComponent($config) { //如果配置项内容是一个字符串,则它是类名,如果是数组,那么数组的class成员是类名 if(is_string($config)) { $type=$config; $config=array(); } else if(isset($config['class'])) { $type=$config['class']; unset($config['class']); } else throw new CException(Yii::t('yii','Object configuration must be an array containing a "class" element.')); //如果类不存在,则使用import来引入,而不是用autoload if(!class_exists($type,false)) $type=Yii::import($type,true); //创建组件时,可以带更多的初始值进行初始化 if(($n=func_num_args())>1) { $args=func_get_args(); if($n===2) $object=new $type($args[1]); else if($n===3) $object=new $type($args[1],$args[2]); else if($n===4) $object=new $type($args[1],$args[2],$args[3]); else { unset($args[0]); $class=new ReflectionClass($type); // Note: ReflectionClass::newInstanceArgs() is available for PHP 5.1.3+ // $object=$class->newInstanceArgs($args); //如果参数大于4个,那么调用newInstance方法来进行初始化 $object=call_user_func_array(array($class,'newInstance'),$args); } } else $object=new $type; //将配置中的配置项赋值给组件的成员 foreach($config as $key=>$value) $object->$key=$value; return $object;
=========================================================================
我们再来看看errorhandler和exceptionhandler:
Yii_PATH/base/CApplication.php
public function handleError($code,$message,$file,$line) { if($code & error_reporting()) { // disable error capturing to avoid recursive errors //恢复原错误handler(内建的错误handler),避免本函数触发错误handler,从而递归调用 restore_error_handler(); restore_exception_handler(); $log="$message ($file:$line)"; if(isset($_SERVER['REQUEST_URI'])) $log.=' REQUEST_URI='.$_SERVER['REQUEST_URI']; Yii::log($log,CLogger::LEVEL_ERROR,'php'); try { //使用一个error事件类来触发error事件,然后显示log信息,这里暂不分析 $event=new CErrorEvent($this,$code,$message,$file,$line); $this->onError($event); if(!$event->handled) { // try an error handler if(($handler=$this->getErrorHandler())!==null) $handler->handle($event); else $this->displayError($code,$message,$file,$line); } } catch(Exception $e) { $this->displayException($e); } $this->end(1); } }
dispalyError代码如下:
public function displayError($code,$message,$file,$line) { //如果是调试,打印调用栈,否则不打印 if(YII_DEBUG) { echo "<h1>PHP Error [$code]</h1>\n"; echo "<p>$message ($file:$line)</p>\n"; echo '<pre>'; debug_print_backtrace(); echo '</pre>'; } else { echo "<h1>PHP Error [$code]</h1>\n"; echo "<p>$message</p>\n"; } }
参考:
设定了error hanlder之后,某些级别的错误是不会触发设置的函数的,例如:E_ERROR(运行期错误,如内存分配错误),E_PARSE(解释错误,即语法),E_CORE_ERROR(在PHP内核startup阶段发生的错误),E_CORE_WARNING(在PHP内核startup阶段发生的warning),E_COMPILE_ERROR(编译错误,zend引擎生成),E_COMPILE_WARNING(编译warning,zend引擎生成) 关于startup和zend引擎请参考php内核方面的资料
handleException与Error相似:
public function handleException($exception) { // disable error capturing to avoid recursive errors restore_error_handler(); restore_exception_handler(); $category='exception.'.get_class($exception); //如果是Http异常,获取状态码 if($exception instanceof CHttpException) $category.='.'.$exception->statusCode; $message=(string)$exception; if(isset($_SERVER['REQUEST_URI'])) $message.=' REQUEST_URI='.$_SERVER['REQUEST_URI']; Yii::log($message,CLogger::LEVEL_ERROR,$category); //接下来同handleError try { $event=new CExceptionEvent($this,$exception); $this->onException($event); if(!$event->handled) { // try an error handler if(($handler=$this->getErrorHandler())!==null) $handler->handle($event); else $this->displayException($exception); } } catch(Exception $e) { $this->displayException($e); } $this->end(1); }
参考:
call_user_function可以传递儿女和内置的或者用户自定义的函数,除了语言结构如array(), echo(), empty(), eval(), exit(), isset(), list(), print(), unset()
上一篇: Yii分析4:run的执行
下一篇: Yii分析1:web程序入口(2)