You may create custom exception subscriber as it is shown below.
Notice that I did not use Drupal theming engine to render the error page. Uncaught exception indicates that something really wrong has happened on a site. There is a great chance that some Drupal services are not available so rendering error page may fail as well.
Also keep in mind that exception subscriber won't catch fatal PHP errors because they are handled differently.
src/EventSubscriber/ExceptionSubscriber.php
<?php
namespace Drupal\example\EventSubscriber;
use Drupal\Core\EventSubscriber\DefaultExceptionSubscriber;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\KernelEvents;
/**
* Last-chance handler for exceptions.
*
* This handler will catch any exceptions not caught elsewhere and send a themed
* error page as a response.
*/
class ExceptionSubscriber extends DefaultExceptionSubscriber {
/**
* {@inheritdoc}
*/
protected function onHtml(GetResponseForExceptionEvent $event) {
if ($this->getErrorLevel() == ERROR_REPORTING_DISPLAY_VERBOSE) {
parent::onHtml($event);
}
else {
$content = file_get_contents(DRUPAL_ROOT . '/../500-error.html');
$response = new Response($content, 500);
$event->setResponse($response);
}
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
// Catch the exception just before default exeception subscriber.
// @see Drupal\Core\EventSubscriber\DefaultExceptionSubscriber::getSubscribedEvents()
$events[KernelEvents::EXCEPTION][] = ['onException', -255];
return $events;
}
}
services.yml
services:
example.exception_subscribtr:
class: Drupal\example\EventSubscriber\ExceptionSubscriber
arguments: ['@serializer', '%serializer.formats%']
tags:
- { name: event_subscriber }
Note that you need to have error reporting set to something other than verbose for this to work (unless you alter the code above). This can either be controlled in the CMS here: /admin/config/development/logging or it may be overridden in your settings.php file. For example, you might need to set
$config['system.logging']['error_level'] = 'hide';
Also note, that if your file_get_contents throws a fatal error, you will get the standard error for uncaught exceptions: "The website encountered an unexpected error. Please try again later."
Here's two ways you can trigger a 500 error for testing:
use Symfony\Component\HttpKernel\Exception\HttpException;
throw new HttpException(500);
or
/** @var \Drupal\Core\Template\TwigEnvironment $environment */
$environment = \Drupal::service('twig');
$environment->loadTemplate('this-template-does-not-exist.html.twig')->render([]);