拉拉维尔自定义异常配置



我一直在尝试在 Laravel 5.3 中实现一些自定义异常,但没有运气。

我创建了一个扩展异常类的AppException。这样做的想法是,我想将用户附加到我的异常中,以便我知道谁跳闸了它并可以记录它。

所以我像这样设置了我的自定义例外:

class AppException extends Exception{
    protected $userId;
    public function __construct($message = '', $userId=0)
    {
        parent::__construct($message);
        $this->userId = $userId;
    }
}

现在我想在我的控制器函数中使用 try catch,然后捕获异常,然后重新引发应用程序异常,以便我可以附加用户。喜欢这个:

try{
    << code here >>
}
catch(Exception $e){
    throw new AppException($e->getMessage, $request->user()->id);
}

我发现我无法获得一个好的跟踪堆栈,因为我从异常中记录的行是来自捕获中重新抛出的行,而不是来自实际异常的行。

设置它的正确方法是什么?我正在尝试以一种可以利用 Laravel 附带的内置 Handler.php 文件的方式执行此操作,而不必在每次尝试捕获中输入日志代码。

谢谢!

Exception 类有一个 previous 参数,可用于检索所有以前的异常。

class AppException extends Exception
{
    private $userId;
    public function __construct($userId, $message = '', $code = 0, Exception $previous = null)
    {
        $this->userId = $userId;
        parent::__construct($message, $code, $previous);
    }
    public static function fromUserId($userId, Exception $previous = null)
    {
        return new static($userId, sprintf('Exception thrown from `%s` userid', $userId), 0, $previous);
    }
    public function getUserId()
    {
        return $this->userId;
    }
}

或者只是简单地

class AppException extends Exception
{
    public static function fromUserId($userId, Exception $previous = null)
    {
        return new static(sprintf('Exception thrown from `%s` userid', $userId), 0, $previous);
    }
}

捕获AppException后,可以像这样迭代所有异常:

do {
    printf("%s:%d %s (%d) [%s]n", $e->getFile(), $e->getLine(), $e->getMessage(), $e->getCode(), get_class($e));
} while($e = $e->getPrevious());

例:

try {
    try{
        throw new RuntimeException('Something bad happened.');
    }
    catch(Exception $e){
        throw AppException::fromUserId(123, $e);
    }
} catch(AppException $e) {
    do {
        printf("%s:%d %s (%d) [%s]n", $e->getFile(), $e->getLine(), $e->getMessage(), $e->getCode(), get_class($e));
    } while($e = $e->getPrevious());
}

尝试将实际异常附加到抛出的异常,例如:

class AppException extends Exception
{
    /**
     * @var int
     */
    private $userId;
    /**
     * @param Exception $exception
     * @param int        $userId
     *
     * @return self
     */
    public static function fromExceptionAndUserId(Exception $exception, $userId)
    {
        $instance = new self(
            $exception->getMessage(),
            0,
            $exception
        );
        $instance->userId = $userId;
        return $instance;
    }
    /**
     * @return null|int
     */
    public function userId()
    {
        return $this->userId;
    }
}

然后在控制器中:

try {
    // ...
} catch (Exception $exception) {
    throw AppException::fromExceptionAndUserId(
        $exception, 
        $request->user()->id
    );
}

这个想法是不仅使用实际的异常消息,而且还将实际的异常附加为$previous异常。

使用命名构造函数的优势在于,您可以控制如何构造AppException的异常消息(同时还附加用户标识符(,并且仍然能够使用原始AppException构造函数。它还使您可以自由地为不同的用例添加更多命名构造函数。

有关参考,请参阅

  • http://php.net/manual/en/class.exception.php
  • http://verraes.net/2014/06/named-constructors-in-php/

最新更新