用户自定义

本章讲介绍一些开发过程中常用需要自定义的东西。

一、自定义404页面

一般比较完整的站点,都会有自定义的404页面,既美观统一、又能保持访问者不至于因为错误页面而退出网站。

比如说duowan.com的404页面,是一个坦克大战的小游戏,可以在线玩并且成绩还会进入排行榜,和其他网友一较高下。

对404错误页面的建议:

  • 建议不要使用PHP动态页面,纯HTML页面会比较好。
  • 具特色,但不能过于复杂的页面,保存页面可以快速载入和有鲜明的提示。
  • 通常会进行一些引导,作为“找不到页面”的补充,但建议不要过多。

在sp框架中,自定义自己程序的404页面,也是很简单的事情。

打开protected/controller/BaseController.php,在BaseController类中,加入以下方法:

  1. public static function err404($module, $controller, $action){
  2. header("HTTP/1.0 404 Not Found");
  3. exit;
  4. }

当你访问到一个不存在的controller/action的时候,就会出现http 404的提示了。

当然你还可以做得更漂亮一点,比如说做个叫404.html的页面,放在模板目录里面。然后修改一下上面的err404()方法:

  1. public static function err404($module, $controller, $action){
  2. header("HTTP/1.0 404 Not Found");
  3. $controlObj = new Controller;
  4. $controlObj->display("404.html");
  5. exit;
  6. }

现在你就可以在404的时候显示你的404.html页面了。

这里不建议去掉header函数输出的404头,因为这样才比较符合一个404页面的规范,并且搜索引擎以及内容分发网络(CDN)等都不会误会成一个普通的页面(只是页面上写着404),从而引发一些没必要的问题。

另外exit也最好保留,因为404之后你就不需要再执行下去了。

二、全局位置

在后面准备讲自定义类库和自定义函数库的知识之前,我们最好能来了解一下关于程序的全局位置。

全局位置的作用一般是:

  • 定义常量:定义在整个程序中使用到的静态常量,如路径的定义、数值的定义等。
  • 载入文件:载入全局都要使用的类库/函数库php文件
  • 执行某些代码:如进行应用程序配置的合并、执行全局函数,GZIP压缩或输出处理等。
  • 全局性的预操作,如权限控制,菜单构造、全局跳转等。

在新版的sp框架里面,全局位置更为单一,因为我们认为全局位置就是一个控制专用的位置,所以它必须处在控制器的范畴内。

新版中我们加入了BaseController这个自带的用户类,它的位置刚好在Controller控制器父类和用户自定义控制器的继承链之间。这样使得BaseController既有普通的Controller的功能,也能覆盖到全部用户控制器之前进行操作。所以BaseController是比较适合当做全局位置的地方。

BaseController有一个初始化执行的方法,名为init(),它会在BaseController构造函数内执行,所以进入控制器后最先执行的位置。

全局定于和全局操作,就可以放在BaseController/init()里面执行。

对比来说,新版的init()和旧版直接使用控制器父类的构造函数,差别并不大。但是直接使用构造函数还是会不太优雅,所以新版加入了init()方法来代替。

三、自定义类库

在之前的快速入门教程中,我们已经讲述过,新版sp框架里面,自定义的类库实际上跟Model模型类一样,只要满足以下条件,都可以直接通过new语法来实例化:

  • 类名和类文件名一致,当然也必须是大小写一致才行。
  • 类文件放在protected下面的model、include、controller之一的目录内。

四、自定义函数库

用户自定义的函数,一般都是比较实用并且经常用到的一些函数集合,如加解密、分片下载、美化时间等函数。

所以我们一般会建议自定义的函数都放到一个函数库文件里面,在“全局位置”中引入该文件(如BaseController的init()函数),这样就在程序的大部分地方都可以轻松调用了——包括新版的模板引擎内。

是的,新版的模板引擎,已经不再需要“注册函数”才能在模板里面用函数了。

这里举个例子,我们为程序引入一个叫mydate()的函数。

  1. <?php
  2. // mydate函数
  3. function mydate($time = null){
  4. if( null == $time )$time = time(); // 默认是当前时间
  5. if( $time > (time() - 3600) ){
  6. return "刚才";
  7. }elseif( $time > (time() - 3600 * 24) ){
  8. return "今天";
  9. }elseif( $time > (time() - 3600 * 24 * 2) ){
  10. return "昨天";
  11. }elseif( $time > (time() - 3600 * 24 * 3) ){
  12. return "前天";
  13. }else{
  14. return date("Y-m-d H:s", $time);
  15. }
  16. }
  17. ?>

将以上代码保存到protected/include/functions.php里面。

functions.php文件和include目录都是不存在的,需要自行创建。

然后在BaseController的init()函数内,将它包含进来:

  1. <?php
  2. class BaseController extends Controller{
  3. function init(){
  4. require(APP_DIR.'/protected/include/functions.php');
  5. }
  6. }
  7. ?>

那么,在程序的控制器以及模板内,都可以正常使用mydate()函数了。

五、自定义错误处理

speedphp拥有标准的错误处理函数,在debug模式下会显示出现的错误,以及详细的错误的过程代码;而在部署模式下,则会直接使用error_log来记录错误信息,然后静默返回执行。

在部署模式的错误静默处理情况下,开发者应该及时关注服务器error_log日志,以便发现问题。

注意:自定义错误处理函数,以及包括speedphp的标准错误处理函数,都无法捕获到php核心错误。

当我们希望能自行控制错误处理时,可以通过配置$config[‘err_handler’]将错误处理转移到自定义函数内处理。

如在config.php内写入:

  1. $config = array(
  2. 'err_handler' => 'hide_err'
  3. );
  4. function hide_err($msg, $traces) {
  5. dump($msg);
  6. dump($traces);
  7. }

那么框架内捕捉到的错误,均会交给hide_err()函数来做处理。

开发者在hide_err()函数内,应自行通过$GLOBALS[‘debug’]的值,对部署模式和调试模式之间的差异进行分别处理。