Laravel 5.1 - 致命错误后未抛出数据库事务异常

Laravel 5.1 - DB transaction exception not thrown after fatal error

我有一个数据库事务,里面有这样一个事件:

    DB::beginTransaction();

    try {
        event(new sendMessage($message, $to, $from));
    }
    catch(\Exception $e)
    {
        return 'error';
    }

    DB::commit();

此事件设置了 2 个工作侦听器;问题是,如果其中一个侦听器出现错误(如果出现问题),例如不正确的变量名,事务的捕获异常 'error' 永远不会 returned,只有实际错误得到已记录,但 'error' 未从交易中 return 编辑。

知道为什么会发生这种情况以及如何解决它,以便如果任何侦听器由于任何原因而失败,则会抛出事务异常吗?

编辑:

所以看起来如果错误是在侦听器中,异常就会被正确抛出。问题似乎是事件构造函数本身是否有错误:

public function __construct(Message $message, $to, $from)
{
    $this->messege = $message; //notice the incorrect messege spelling
    $this->to = $to;
    $this->from = $from;
}

我原以为数据库事务会抛出异常,但它却被记录了下来:

[2015-07-29] local.ERROR: exception 'Symfony\Component\Debug\Exception\FatalErrorException' with message 'Call to a member function message() on null' in */Listeners/Messages/CreateMessage.php:38

其中 CreateMessage.php 是一个使用变量 $message 的侦听器。

class CreateMessage {
    public function __construct()
    {
        //
    }

    public function handle(sendMessage $event)
    {
        $event->message->message()->create([  // Exception above get thrown because of the 'messege' typo in the event
            'to'      => $event->to,
            'from'    => $event->from
        ]);
    }
}

所以最后一个问题是,如果存在这样的情况,事件侦听器使用的变量名中有拼写错误,我该如何 return 数据库事务错误?

好的。你无法捕获致命错误。继续执行脚本是没有办法的。 因为它们出现后脚本不再执行。 所以你可以理解为:

在这个字符串之后

$event->message->create(

您的代码"not exists"。 还有你的 catch(\Exception $e) "not exists"。 请参阅此处的 1 16 64 4096 行说明 http://php.net/manual/en/errorfunc.constants.php

在出现致命错误后做某事(但不是你想要的)的唯一方法是使用 register_shutdown_function

并且 laravel 最后要做的就是抛出这个例外

'Symfony\Component\Debug\Exception\FatalErrorException' with message 'Call to a member function message() on null' in */Listeners/Messages/CreateMessage.php:38

但是你无法捕捉到它,之后脚本停止了。 就是这样。

让我们看看我们在 Laravel-core:

中有什么

vendor\laravel\framework\src\Illuminate\Foundation\Bootstrap\HandleExceptions.php

public function bootstrap(Application $app)
{
    $this->app = $app;

    error_reporting(-1);

    set_error_handler([$this, 'handleError']);

    set_exception_handler([$this, 'handleException']);

    register_shutdown_function([$this, 'handleShutdown']);

    if (!$app->environment('testing')) {
        ini_set('display_errors', 'Off');
    }
}

我们对 register_shutdown_function([$this, 'handleShutdown']); 感兴趣:

/**
 * Handle the PHP shutdown event.
 *
 * @return void
 */
public function handleShutdown()
{
    if (!is_null($error = error_get_last()) && $this->isFatal($error['type'])) {
        $this->handleException($this->fatalExceptionFromError($error, 0));
    }
}

这里我们感兴趣的是$this->fatalExceptionFromError($error, 0):

/**
 * Create a new fatal exception instance from an error array.
 *
 * @param  array  $error
 * @param  int|null  $traceOffset
 * @return \Symfony\Component\Debug\Exception\FatalErrorException
 */
protected function fatalExceptionFromError(array $error, $traceOffset = null)
{
    return new FatalErrorException(
        $error['message'], $error['type'], 0, $error['file'], $error['line'], $traceOffset
    );
}

看看这个:

* @return \Symfony\Component\Debug\Exception\FatalErrorException

他们抛出与您收到的完全相同的异常