在类中为特定异常子类设置异常处理程序


Set an exception handler in a class for a specific exception subclass

>我在PHP项目中有一个简单的类,它在其构造函数中使用了类似以下内容的内容:

    @set_exception_handler(array($this, 'exception_handler'));

问题是,它在全局范围内捕获异常,例如:与类完全无关的异常。

是否可以在此处限制仅由此类和/或特定异常子类的实例引发的异常范围,例如:MyClassException

不能只为自己的异常设置异常处理程序。所有处理程序都在全局范围内工作。但是,您可以创建自己的异常处理程序链并控制所有异常。

<?php
interface ExceptionHandlerInterface
{
    public function supports('Exception $e);
    public function handle('Exception $e);
}
class ExceptionHandler implements ExceptionHandlerInterface
{
    public function supports('Exception $e)
    {
        return $e instanceof 'Exception;
    }
    public function handle('Exception $e)
    {
        throw $e;
    }
}
class MyExceptionHandler implements ExceptionHandlerInterface
{
    public function supports('Exception $e)
    {
        return $e instanceof MyException;
    }
    public function handle('Exception $e)
    {
        exit("Oops, this is a my exception.'n");
    }
}
class ExceptionHandlerChain
{
    private $handlers;
    public function addHandler(ExceptionHandlerInterface $handler, $priority)
    {
        // you should sort all handlers with priority
        $this->handlers[] = $handler;
    }
    public function handle('Exception $e)
    {
        foreach ($this->handlers as $handler) {
            if ($handler->supports($e)) {
                $handler->handle($e);
            }
        }
    }
}

class MyException extends 'Exception
{
}
$chain = new ExceptionHandlerChain();
$chain->addHandler(new MyExceptionHandler(), 0);
$chain->addHandler(new ExceptionHandler(), 1024);
set_exception_handler([$chain, 'handle']);
//throw new RuntimeException();
throw new MyException();

正如我在上面的评论中所说,您不能以某种方式将全局异常处理程序限制为特定的异常类型或事件。

但是,您可以使用phps神奇的__call()方法来实现类似的东西,而不必在所有类方法中使用普通的try...catch块。考虑这个简单的例子:

<?php
class myException extends Exception {}
class myClass
{
  public function __call($funcName, $funcArgs)
  {
    try {
      if (method_exists($this, '_'.$funcName)) {
          $this->_myFunction($funcArgs);
      }
    } catch (myException $e) {
      var_dump($e->getMessage());
    }
  }
  public function _myFunction($args)
  {
      throw new myException('Ooops');
  }
}
$myObj = new myClass;
$myObj->myFunction();

这里的输出显然是:

string(5) "Ooops"

这里有三点需要指出:

  1. _myFunction()这样的"正常"方法不必实现try...catch
  2. 捕获的异常可以限制为某些类型,并且可以在对象范围内处理
  3. 未注册全局异常处理程序,因此不会捕获全局异常。

但是,这种设置的一个巨大缺点是,IDE 无法支持此类方法链,因此您不会获得自动完成功能,也不会获得对象方法的签名帮助。