我一直在尝试在 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/