您的位置:首页 > 编程语言 > PHP开发

9:Yii中的主题、日志、性能分析以及错误处理(Yii权威指南)

2013-05-05 10:29 507 查看
Theming(主题)
在Yii,每个主题由一个目录代表,包含view文件,layout文件和相关的资源文件,如图片, CSS文件, JavaScript文件等。主题的名字就是他的目录名字。全部主题都放在在同一目录WebRoot/themes下 。在任何时候,只有一个主题可以被激活。

提示:默认的主题根目录WebRoot/themes可被配置成其他的。只需要配置themeManager应用部件的属性basePathbaseUrl为你所要的值。要激活一个主题,设置Web应用程序的属性theme为你所要的名字。可以在application
configuration中配置或者在执行过程中在控制器的动作里面修改。
主题目录里面内容的组织方式和application base path目录下的组织方式一样。例如,所有的view文件必须位于views下 ,布局view文件在views/layouts下
,和系统view文件在views/system下。例如,如果我们要替换PostController的create view文件为classic主题下,我们将保存新的view文件为WebRoot/themes/classic/views/post/create.php。
对于在module里面的控制器view文件,相应主题view文件将被放在views目录下。例如,如果上述的PostController是在一个命名为forum的模块里
,我们应该保存create view 文件为WebRoot/themes/classic/views/forum/post/create.php 。如果 forum模块嵌套在另一个名为support模块里 ,那么view文件应为WebRoot/themes/classic/views/support/forum/post/create.php 。
注:由于views目录可能包含安全敏感数据,应当配置以防止被网络用户访问。
当我们调用renderrenderPartial显示视图,相应的view文件以及布局文件将在当前激活的主题里寻找。如果发现,这些文件将被render渲染。否则,就后退到viewPathlayoutPath 所指定的预设位置寻找。
baseurl属性:
在一个主题的视图,我们经常需要链接其他主题资源文件。例如,我们可能要显示一个在主题下images目录里的图像文件。使用当前激活主题的baseurl属性,我们就可以为此图像文件生成如下url,
yii: :app()->theme->baseUrl
. '/images/FileName.gif'

下面是2个主题的文件目录列表:
WebRoot/
assets
protected/
.htaccess
components/
controllers/
models/
views/
layouts/
main.php
site/
index.php
themes/
basic/
views/
.htaccess
layouts/
main.php
site/
index.php
fancy/
views/
.htaccess
layouts/
main.php
site/
index.php
在配置文件里面(注意这个配置文件就是main.php,俗称应用配置,而不需要在组件里面配置什么),我们可以这样写:
return array(
'theme'=>'basic',
......
);
配置完成就会使basic主题生效,应用将会使用这个布局themes/basic/views/layouts, 并且site index也会换成主题下面的themes/basic/views/site. 如果在主题里面没有发现view文件,这它会继续在protected/views目录下面进行寻找渲染。

主题小部件(Theme Widgets)
从1.1.5版本开始,views可以使用widget主题。特别当我们调用CWidget::render() 来显示一个widget试图时,Yii会尝试寻找主题文件和Widget文件夹下的view文件。

对于主题试图xyz来说,如果显示它的widget的类名是Foo,我们首先应该在当前的主题下创建一个Foo的文件夹(必须和Widget类名一样). If the widget class is namespaced (available in PHP 5.3.0 or above), such as \app\widgets\Foo, we should create a folder namedapp_widgets_Foo.
That is, we replace the namespace separators with the underscore characters.

We then create a view file named xyz.php under the newly created folder. To this end, we should have a filethemes/basic/views/Foo/xyz.php, which will be used by the widget to replace its original view, if the currently active theme is basic.

日志记录
1. 信息记录
信息可以通过 Yii::logYii::trace 记录。其 区别是后者只在当应用程序运行在 调试模式(debug
mode) 中时才会记录信息。
Yii::log($message,$level,
$category);
Yii::trace($message,$category);
当记录信息时,我们需要指定它的分类和级别 分类是一段格式类似于 路径别名 的字符串。 例如,如果一条信息是在 CController 中记录的,我们可以使用 system.web.CController 作为分类。信息级别应该是下列值中的一种:

trace: 这是在 Yii::trace 中使用的级别。它用于在开发中 跟踪程序的执行流程。
info: 这个用于记录普通的信息。
profile: 这个是性能概述(profile)。下面马上会有更详细的说明。
warning: 这个用于警告(warning)信息。
error: 这个用于致命错误(fatal error)信息。

2. 信息路由
通过 Yii::logYii::trace 记录的信息是保存在内存中的。 我们通常需要将它们显示到浏览器窗口中,或者将他们保存到一些
持久存储例如文件、Email中。这个就叫作 信息路由,例如, 发送信息到不同的目的地。
在 Yii 中,信息路由是由一个叫做 CLogRouter 的应用组件管理的。 它负责管理一系列称作 日志路由 的东西。每个日志路由 代表一个单独的日志目的地。通过一个日志路由发送的信息会被他们的级别和分类过滤。
要使用信息路由,我们需要安装并预加载一个 CLogRouter 应用组件。我们也还需要配置它的 routes 属性为我们想要的那些日志路由。
下面的代码演示了一个所需的 应用配置 示例:
array(
......
'preload'=>array('log'),
'components'=>array(
......
'log'=>array(
'class'=>'CLogRouter',
'routes'=>array(
array(
'class'=>'CFileLogRoute',
'levels'=>'trace, info',
'categories'=>'system.*',
),
array(
'class'=>'CEmailLogRoute',
'levels'=>'error, warning',
'emails'=>'admin@example.com',
),
),
),
),
)
在上面的例子中,我们定义了两个日志路由。第一个是 CFileLogRoute ,它会把信息保存在位于应用程序 runtime 目录中的一个文件中。 而且只有级别为 trace 或 info 、分类以 system. 开头的信息才会被保存。
第二个路由是 CEmailLogRoute ,它会将信息发送到指定的 email 地址,且只有级别为 error 或 warning 的才会发送。
在 Yii 中,有下列几种日志路由可用:

CDbLogRoute: 将信息保存到数据库的表中。
CEmailLogRoute: 发送信息到指定的 Email 地址。
CFileLogRoute: 保存信息到应用程序 runtime 目录中的一个文件中。
CWebLogRoute: 将 信息 显示在当前页面的底部。
CProfileLogRoute: 在页面的底部显示概述(profiling)信息。

注:信息路由发生在当前请求周期最后的 onEndRequest 事件触发时。 要显式终止当前请求过程,请调用 CApplication::end() (我测试出来是使用Yii::app()->end();退出) 而不是使用 die() 或exit(),因为 CApplication::end() 将会触发 onEndRequest 事件, 这样信息才会被顺利地记录。

3. 信息过滤
正如我们所提到的,信息可以在他们被发送到一个日志路由之前通过它们的级别和分类过滤。 这是通过设置对应日志路由的 levelscategories 属性完成的。
多个级别或分类应使用逗号连接。
由于信息分类是类似 xxx.yyy.zzz 格式的,我们可以将其视为一个分类层级。 具体地,我们说 xxx 是 xxx.yyy的父级,而xxx.yyy 又是 xxx.yyy.zzz 的父级。 这样我们就可以使用 xxx.* 表示分类 xxx 及其所有的子级和孙级分类
4. 记录上下文信息

从版本 1.0.6 起,我们可以设置记录附加的上下文信息, 比如 PHP 的预定义变量(例如 $_GET, $_SERVER),session ID,用户名等。 这是通过指定一个日志路由的 CLogRoute::filter属性为一个合适的日志过滤规则实现的。

框架可以使用一个 CLogFilter 来处理日志的上下文信息,CLogFilter 默认可以记录一些变量例如$_GET,$_SERVER
。 但是我们可以配置它使它可以记录更多的信息如 session ID, username 等等。
下面的配置告诉我们如何配置一个记录上下文信息的日志。注意其实每个log route可以有它们自己的log filter。默认log route是没有log filter的。
array(
......
'preload'=>array('log'),
'components'=>array(
......
'log'=>array(
'class'=>'CLogRouter',
'routes'=>array(
array(
'class'=>'CFileLogRoute',
'levels'=>'error',
'filter'=>'CLogFilter',
),
...other
log routes...
),
),
),
)

5. 性能分析(Performance Profiling)
性能分析是一种特别的日志消息,它可以测量一些指定的code blocks 或者找出哪些是影响性能的代码。
使用性能分析,我们仅需要指定出哪些code blocks需要被分析,然后再代码块的开头和结尾插入相应的方法,例如:
Yii::beginProfile('blockID');
...code blockbeing
profiled...
Yii::endProfile('blockID');
blockID是唯一的,指向这个代码块的。为了显示分析结果,我们需要安装 CLogRouter 应用组件的 CProfileLogRoute log
route功能。这个CProfileLogRoute和我们配置普通的信息routes是一样的。 CProfileLogRoute route
将会显示性能测试结果在当前页面的最下面。
main.php的配置:
log'=>array(
'class'=>'CLogRouter',
'routes'=>array(
array(
'class'=>'CProfileLogRoute',
),
array(
'class'=>'CFileLogRoute',
'levels'=>'error, warning',
),
),
),

Controller里面的代码块:
public function actionIndex()
{
// renders the view file 'protected/views/site/index.php'
// using the default layout 'protected/views/layouts/main.php'

Yii::beginProfile('index');
echo 123;
$this->render('index',array('callback'=>'xiaozhe'));
echo 345;
Yii::endProfile('index');
}
6. SQL分析(Profiling SQL Executions)
一般在一个应用里面,SQL的执行时一个主要的性能瓶颈,所以使用SQL分析是非常有用的。我们可以手动的插入beginProfile and endProfile 语句在适当的地方来测量SQL语句执行花费的时间,从1.0.6开始,Yii提供一个更加系统的方法来解决这个问题。
我们可以在应用配置(Application Config)里面设置 CDbConnection::enableProfiling 为true,这样的话每个SQL执行命令都会被分析。分析结果可以使用CProfileLogRoute来显示出来。我们也可以调用CDbConnection::getStats() 来检索所有的SQL执行以及花费的时间(在controller里面可以这样用:$str
= Yii::app()->db->getStats(); var_dump($str);)。
例如:
main.php中配置CDbConnection:
'db'=>array(
'connectionString' => 'mysql:host=localhost;dbname=testdrive',
'emulatePrepare' => true,
'username' => 'root',
'password' => 'xiaozhe',
'charset' => 'utf8',
'tablePrefix' => 'tbl_',

//主要是下面的2句话
'enableProfiling'=>true,
'enableParamLogging'=>true,
),

main.php中配置Log来显示数据:
log'=>array(
'class'=>'CLogRouter',
'routes'=>array(
//数据库的信息也是CProfileLogRoute来显示
array(
'class'=>'CProfileLogRoute',
),
array(
'class'=>'CFileLogRoute',
'levels'=>'error, warning',
),
),
),

最后在Controller里面进行代码块选定:
public function actionIndex()
{
Yii::beginProfile('id');

$dataProvider=new CActiveDataProvider('Post');
$this->render('index',array(
'dataProvider'=>$dataProvider,
));

Yii::endProfile('id');
}

错误处理
提示: 错误处理器的注册是在应用中的constructor方法中进行的,使用了PHP函数set_exception_handler 和set_error_handler。 如果你不想让Yii来处理错误和异常,你可以在入口文件中定义YII_ENABLE_ERROR_HANDLER和YII_ENABLE_EXCEPTION_HANDLER为false.

默认情况下,在触发onError事件(或onException事件)的时候,errorHandler(或exceptionHandler)将被触发。如果错误或者异常未被任何事件所处理,那么就需要运行errorHandler组件来处理了。

1. 引发异常
在Yii中引发异常和在普通PHP文件中没什么两样。你可以使用下面的代码来抛出异常:
throw
new ExceptionClass('错误信息');
Yii定义了两个异常类:CExceptionCHttpException。前者是一个通用的异常类,而后者用于对最终用户显示异常信息。同时,后者有一个statusCode属性来代表HTTP状态码。异常的类型决定了显示效果,下面会细说。
// 如果提交的ID是无效的
throw
new CHttpException(404,'此页面不存在');

2. 显示错误
当一个错误被转发给组件CErrorHandler的时候,它会选择合适的视图来显示错误。如果这个错误要显示给最终用户的(比如说一个CHttpException)那么会使用名为errorXXX的视图来显示错误。这个XXX代表着HTTP错误码(比如说400,404,500等)。如果这是个内部错误,应该只能被开发者看到,那么将使用的视图名是exception。在后一种中,将会显示完整的调用栈信息和错误行信息。
CErrorHandler会搜索合适的视图来显示错误信息,搜索的顺序如下:

WebRoot/themes/ThemeName/views/system: 在当前主题视图下的system目录中。
WebRoot/protected/views/system: 在应用的默认视图的system目录中。
yii/framework/views: 在Yii提供的标准视图目录中。

因此,如果你想要自定义错误显示,可以直接在system视图目录中或者主题的system视图目录中创建一个视图文件。每个视图文件都是一个包含许多HTML代码的普通PHP文件。参考框架的view目录下的文件,可以获得更多信息。

3. 使用一个动作来处理错误
Yii也可以使用控制器 动作来处理错误显示。实现的方法是在应用的配置文件中配置一个错误处理器。
return array(
......
'components'=>array(
'errorHandler'=>array(
'errorAction'=>'site/error',
),
),
);
上面的代码中,我们配置了CErrorHandler::errorAction属性,属性值是一个路由site/error。这个路由指向SiteController中的error。当然,你也可以使用其他的路由。

我们可以这样来编写error动作:
public functionactionError()
{
if($error=Yii::app()->errorHandler->error)
$this->render('error',$error);
}
在这个动作中,首先从CErrorHandler::error中取得详细的错误信息。如果取得的信息非空,就使用CErrorHandler::error返回的信息来渲染error视图。CErrorHandler::error返回的信息是一个数组,结构如下:

code: HTTP 状态码(比如 403, 500);
type: 错误类型(比如 CHttpException, PHP Error);
message: 错误信息;
file: 发生错误的PHP文件名;
line: 错误所在的行;
trace: 错误的调用栈信息;
source: 发生错误的代码的上下文。

4. 消息记录
一个error级别的错误信息会在错误发生时候被记录。如果这个错误是由PHP warning 或 notice引发的,那么这个消息将会被记录在php这个分类中;如果错误信息是由未捕获的异常所引起的,那么分类将是exception.ExceptionClassName(对于CHttpException来说,它的statusCode也将被追加到分类名中)。开发者可以使用这些记录来监测应用执行时候的错误信息。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: