1面向对象思想的核心概念3 PHP核心技术与最佳实践

正文开始


1.6.4 PHP中的错误处理机制

    PHP里有一套错误处理机制,可以使用set_error_handler接管PHP错误处理,也可以使用trigger_error函数主动抛出一个错误。

    set_error_handler()函数设置用户自定义的错误处理函数。函数用于创建运行期间的用户自己的错误处理方法。它需要先创建一个错误处理函数,然后设置错误级别。语法如下:

    set_error_handler(error_function,error_types)

    参数描述如下:

    error_function:规定发生错误时运行的函数。必需。

    error_types:规定在哪个错误报告级别会显示用户定义的错误。可选。默认为“E_ALL”。

    提示 如果使用该函数,会完全绕过标准PHP错误处理函数,如果有必要,用户定义的错误处理程序必须终止(die())脚本。

    如果在脚本执行前发生错误,由于在那时自定义程序还没有注册,因此就不会用到这个自定义错误处理程序。这先实现一个自定义的异常处理函数,如代码清单1-21所示。

    代码清单1-21 自定义的异常处理函数
      
    <?php

    function customError($errno, $errstr, $errfile, $errline)

    {

    echo "错误代码: [${errno}] ${errstr}\r\n";

    echo " 错误所在的代码行: {$errline} 文件{$errfile}\r\n";

    echo " PHP版本 ",PHP_VERSION, "(" , PHP_OS, ")\r\n";

    // die();

    }

    set_error_handler("customError",E_ALL| E_STRICT);

    $a = array('o'=>2, 4, 6, 8);

    echo $a[o];

    在这个函数里,可以对错误的详情进行格式化输出,也可以做任何要做的事情,比如判断当前环境和权限给出不同的错误提示,可使用errer_log函数将错误记入log文件,还可以细化处理,针对$errno的不同进行对应的处理。

    自定义的错误处理函数一定要有这四个输入变量$errno、$errstr、$errfile、$errline。

    errno是一组常量,代表错误的等级,同时也有一组整数和其对应,但一般使用其字符串值表示,这样语义更好一点。比如E_WARNING,其二进制掩码为4.,表示警告信息。

    接下来,就是将这个函数作为回调参数传递给set_error_handler。这样就能接管PHP原生的错误处理函数了。要注意的是,这种托管方式并不能托管所有种类的错误,如E_ERROR、E_PARSE、E_CORE_ERROR、E_CORE_WARNING、E_COMPILE_ERROR、E_COMPILE_WARNING,以及E_STRICT中的部分。这些错误会以最原始的方式显示,或者不显示。

    set_error_handler函数会接管PHP内置的错误处理,你可以在同一个页面使用restore_error_handler();取消接管。

    注意 如果使用自定义的set_error_handler接管PHP的错误处理,先前代码里的错误抑制@将失效,这种错误也会被显示。

    在PHP异常中,异常处理机制是有限的,无法自动抛出异常,必须手动进行,并且内置异常有限。PHP把许多异常看做错误,这样就可以把这些“异常”像错误一样用set_error_handler接管,进而主动抛出异常。代码如下所示:

    function customError($errno, $errstr, $errfile, $errline)

    {

    // 自定义错误处理时,手动抛出异常

    throw new Exception($level.'|'.${errstr});

    }

    set_error_handler("customError",E_ALL| E_STRICT);

    try

    {

    $a=5/0;

    }

    catch(Exception $e)

    {

    echo '错误信息:', $e->getMessage();

    }

    这样就能捕获到异常和非致命的错误,就能按照1.6.1节里讲述的方法进行处理了,这样可以弥补PHP异常处理机制的部分不足。

    这种“曲折迂回”的处理方式存在的问题就是:必须依靠程序员自己来掌控对异常的处理,对于异常高发区、敏感区,如果程序员处理不好,就会导致前面所提到的业务数据不一致的问题。其优点在于,可以获得程序运行时的上下文信息,以进行针对性的补救。

    fetal error这样的错误虽然捕获不到,也无法在发生此错误后恢复流程处理,但是还是可以使用一些特殊方法对这种错误进行处理的。这需要用到一个函数——register_shutdown_function,此函数会在PHP程序终止或者die时触发一个函数,给PHP来一个短暂的“回光返照”。在PHP 4的时代,类不支持析构函数,常用这个函数模拟实现析构函数。实例代码如下:

    <?php

    class Shutdown

    {

    public function stop()

    {

    if(error_get_last())

    {

    print_r(error_get_last());

    }

    die('Stop.');

    }

    }

    register_shutdown_function(array(new Shutdown(), 'stop'));

    $a = new a(); // 将因为致命错误而失败

    echo '必须终止';

    可以运行看看效果。对于fetal error还能做点收尾工作,但是PHP流程的终止是必然的。对于Parse error级别的错误,你只有傻眼了,除了可以修改配置文件php.ini,什么都做不了,修改的内容如下:

    log_errors = On

    error_log = usr/log/php.log

    这样一旦PHP发生了错误,就会被记入log文件,方便以后查询。

    和exception类似,错误处理也有对应抛出错误的函数,那就是trigger_error函数,如下所示:

    <?php

    $divisor=0;

    if ($divisor == 0) {

    trigger_error("Cannot divide by zero", E_USER_ERROR);

    }

    echo 'break';

    关于错误处理,主要就是这些内容,还有一些错误处理和调试相关,我们将会放到后面的章节进行讲解。

    提示 在PHP中,错误和异常是两个不同的概念,这种设计从根本上导致了PHP的异常和其他语言相异。以Java为例,Java中,异常是错误唯一的报告方式。说到底,两者的区别就是对异常和错误的认识不同而产生的。PHP的异常绝大部分必须通过某种办法手动抛出,才能被捕获到,是一种半自动化的异常处理机制。

    无论是错误还是异常,都可以使用handler接管系统已有的处理机制。

1.7 本章小结

本章主要介绍面向对象思想的程序的组成元素——类和对象。类是一个动作和属性的模板,对象是数据的集合。结合PHP自身实际情况,着重讲述PHP里面向对象的一些比较模糊的知识点,包括魔术方法、接口、多态、类的复用、反射、异常机制等。接口是一种类型,从接口的实现讲述接口是怎么实现“即插即用”的。

然后,对异常机制进行探讨。讲述异常应该是什么样的,应该怎么用,并且阐述了PHP中的异常为什么会这样,应该在什么场合使用异常等。PHP起初没有异常机制,后期为了进军企业级开发,才模仿Java加进去的,故有了错误处理和异常处理的并存,这种形式导致PHP异常处理不伦不类,通过和Java对比,让我们了解到了异常的真实含义。错误处理是对异常处理的一种补充。

到底面向过程和面向对象孰优孰劣呢?答案是:二者间并无高低优劣之别,它们各有优劣。

其实在OO发展中,暴露出一些问题,如深入对象内部读写状态存在的困难,现实和开发中不对应造成的建模困难,数据与逻辑绑定造成的类型臃肿。比如前面提到的反射,就是因为面向对象的封装导致读写内部状态比较困难而产生的。

面向对象存在的问题是越来越多的语言引入函数式编程的特征,如闭包、回调等。PHP也引入一些函数式编程的概念,有兴趣的读者可以自行研究。




正文结束

1面向对象思想的核心概念2 PHP核心技术与最佳实践 Windows服务器环境Apache下access.log文件太大的解决方法