深入PHP面向对象、模式与实践——高级特性(3)

错误处理

PHP5引入了异常(exception),异常是从PHP5内置的Exception类(或其子类)实例化得到的特殊对象。Exception类型的对象用于存放和报告错误信息。Exception类的构造方法接受两个可选的参数:信息字符串和错误代码。这个类提供了一些有用的方法来分析错误条件。Exception类提供的错误通知和调试信息(特别是getTrace()和getTraceAsString()方法返回到信息)还有用。

  • 抛出异常
    可以联合使用throw关键字和Exception对象来抛出异常。这会停止执行当前方法,并负责将错误返会给调用代码。
//conf01.xml
<?xml version="1.0" ?>
<conf>
    <item name="user">bob</item>
    <item name="pass">newpass</item>
    <item name="host">localhost</item>
</conf>
class Conf
{
    private $file;
    private $xml;
    private $lastmatch;

    public function __construct($file)
    {
        $this->file = $file;
        if (!file_exists($file)) {
            throw new Exception("file 'file' does not exist");
        }
        $this->xml = simplexml_load_file($file);
    }

    public function write()
    {
        if (!is_writable($this->file)) {
            throw new Exception("file '{$this->file}' is not writeable");
        }
        file_put_contents($this->file, $this->xml->asXML());
    }

    public function get($str)
    {
        $matches = $this->xml->xpath("/conf/item[@name=\"$str\"]");
        if (count($matches)) {
            $this->lastmatch = $matches[0];
            return (string) $matches[0];
        }
        return null;
    }

    public function set($key, $value)
    {
        if (!is_null($this->get($key))) {
            $this->lastmatch[0] = $value;
            return;
        }
        $conf = $this->xml->conf;
        $this->xml->addChild('item', $value)->addAttribute('name', $key);
    }
}

__construct()和write()方法可以在工作时不停地检查文件错误,而让其他更合适的代码来响应检测到的错误。如果调用可能抛出异常的方法,那么可以把调用语句放在try子句中。try子句由关键字try及其后的括号组成。try子句必须跟着至少一个catch子句才能处理错误:

try {
    $conf = new Conf(dirname(__FILE__) . "/conf01.xml");
    print "user: " . $conf->get('user') . "\n";
    print "host: " . $conf->get('host') . "\n";
    $conf->set("pass", "newpass");
    $conf->write();
} catch (Exception $e) {
    die($e->__toString());
}
  • 异常的子类化
    如果要创建用户自定义的异常类,可以从Exception类继承。
    实际上,定义多个catch子句时,也只需要一个try子句。调用哪个catch子句取决于抛出异常的类型和参数中类的类型提示。下面我们定义Exception的一些简单子类:
class XmlException extends Exception
{
    private $error;

    public function __construct(LibXmlError $error)
    {
        $shortfile   = basename($error->file);
        $msg         = "[{$shortfile},line {$error->line},col {$error->column}]{$error->message}";
        $this->error = $error;
        parent::__construct($msg, $error->code);
    }

    public function getLibXmlError()
    {
        return $this->error;
    }
}

class FileException extends Exception
{
}

class ConfException extends Exception
{
}

当SimpleXml扫描到一个损坏的XML文件时,会生成LibXmlError对象。现在在代码中使用这些异常类,并修改__construct()和write():

class Conf
{
    //...
    public function __construct($file)
    {
        $this->file = $file;
        if (!file_exists($file)) {
            throw new Exception("file 'file' does not exist");
        }
        $this->xml = simplexml_load_file($file,null,LIBXML_NOERROR);
        if (!is_object($this->xml)) {
            throw new XmlException(libxml_get_last_error());
        }
        print gettype($this->xml);
        $matches=$this->xml->xpath("/conf");
        if (!count($matches)) {
            throw new ConfException("could not find root element: conf");   
        }
    }

    public function write()
    {
        if (!is_writable($this->file)) {
            throw new FileException("file '{$this->file}' is not writeable");
        }
        file_put_contents($this->file, $this->xml->asXML());
    }
    //...

__construct()根据遇到的错误类型,抛出XmlException、FileException或ConfException。可选参数LIBXML_NOERROR给simplexml_load_file(),用于一直出错警告的直接输出,并在警告发生之后留给XmlException类来处理。遇到一个不规范的XML文件时,simplexml_load_file()不会返回对象,这样我就知道发生了错误,然后用libxml_get_last_error()访问错误。

如果$file属性指向一个不可写的文件,你们write()方法就会抛出FileException。

class Runner
{

    public function init()
    {
        try {
            $conf = new Conf(dirname(__FILE__) . "/conf01.xml");
            print "user: " . $conf->get('user') . "\n";
            print "host: " . $conf->get('host') . "\n";
            $conf->set("pass", "newpass");
            $conf->write();
        } catch (FileException $e) {
            //文件权限问题或者文件不存在
        } catch (XmlException $e) {
            //XML文件损坏
        } catch (ConfException $e) {
            //错误的XML文件格式
        } catch (Exception $e) {
            //后备捕捉器,正常情况下不应该被调用
        }
    }
}

catch子句的调用取决于抛出的异常类型。第一个匹配的类型子句将会被执行,所以记得要把通用的类型放到最后,特定的类型放到前面。另外,有关于“后备”(backstop)子句通常是个好办法,以防开发时在代码中要增加新的异常。如果异常到最后也没有被捕获,那么将发生致命错误。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值