Skip to content

Commit d216423

Browse files
committed
minor #12187 Documenting ErrorRenderer and ErrorHandler components (javiereguiluz, yceruto)
This PR was merged into the 4.4 branch. Discussion ---------- Documenting ErrorRenderer and ErrorHandler components Replace #11864 Closes #12193 #12009 #11980 #12015 #12019 #12029 Should we remove the whole Debug component documentation? or remove only the details and say it's deprecated? Commits ------- 8cc084f documenting the ErrorHandler::call method 3ea9817 fix service definition 5a025c9 fix example 5136a17 Update with latest changes: ErrorRenderer and ErrorHandler components b0723ef Fixed a method name b600b3c Renamed ErrorCatcher as ErrorRenderer 4e333c1 Fixes b2a1a9b Documented the ErrorCatcher component
2 parents e5fa340 + 8cc084f commit d216423

File tree

6 files changed

+320
-60
lines changed

6 files changed

+320
-60
lines changed

components/debug.rst

Lines changed: 5 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Installation
1212

1313
.. code-block:: terminal
1414
15-
$ composer require symfony/debug
15+
$ composer require --dev symfony/debug
1616
1717
.. include:: /components/require_autoload.rst.inc
1818

@@ -26,64 +26,13 @@ Enable all of them by calling this method::
2626

2727
Debug::enable();
2828

29-
The :method:`Symfony\\Component\\Debug\\Debug::enable` method registers an
30-
error handler, an exception handler and
31-
:ref:`a special class loader <component-debug-class-loader>`.
32-
33-
Read the following sections for more information about the different available
34-
tools.
35-
3629
.. caution::
3730

3831
You should never enable the debug tools, except for the error handler, in a
3932
production environment as they might disclose sensitive information to the user.
4033

41-
Enabling the Error Handler
42-
--------------------------
43-
44-
The :class:`Symfony\\Component\\Debug\\ErrorHandler` class catches PHP errors
45-
and converts them to exceptions (of class :phpclass:`ErrorException` or
46-
:class:`Symfony\\Component\\Debug\\Exception\\FatalErrorException` for PHP
47-
fatal errors)::
48-
49-
use Symfony\Component\Debug\ErrorHandler;
50-
51-
ErrorHandler::register();
52-
53-
This error handler is enabled by default in the production environment when the
54-
application uses the FrameworkBundle because it generates better error logs.
55-
56-
Enabling the Exception Handler
57-
------------------------------
58-
59-
The :class:`Symfony\\Component\\Debug\\ExceptionHandler` class catches
60-
uncaught PHP exceptions and converts them to a nice PHP response. It is useful
61-
in debug mode to replace the default PHP/XDebug output with something prettier
62-
and more useful::
63-
64-
use Symfony\Component\Debug\ExceptionHandler;
65-
66-
ExceptionHandler::register();
67-
68-
.. note::
69-
70-
If the :doc:`HttpFoundation component </components/http_foundation>` is
71-
available, the handler uses a Symfony Response object; if not, it falls
72-
back to a regular PHP response.
73-
74-
.. _component-debug-class-loader:
75-
76-
Debugging a Class Loader
77-
------------------------
78-
79-
The :class:`Symfony\\Component\\Debug\\DebugClassLoader` attempts to
80-
throw more helpful exceptions when a class isn't found by the registered
81-
autoloaders. All autoloaders that implement a ``findFile()`` method are replaced
82-
with a ``DebugClassLoader`` wrapper.
83-
84-
Using the ``DebugClassLoader`` is done by calling its static
85-
:method:`Symfony\\Component\\Debug\\DebugClassLoader::enable` method::
86-
87-
use Symfony\Component\Debug\DebugClassLoader;
34+
.. deprecated:: 4.4
8835

89-
DebugClassLoader::enable();
36+
In Symfony versions before 4.4, this component also provided error and
37+
exception handlers. In Symfony 4.4 they were deprecated in favor of their
38+
equivalent handlers included in the new :doc:`ErrorHandler component </components/error_handler>`.

components/error_handler.rst

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
.. index::
2+
single: Debug
3+
single: Error
4+
single: Exception
5+
single: Components; ErrorHandler
6+
7+
The ErrorHandler Component
8+
==========================
9+
10+
The ErrorHandler component provides tools to manage errors and ease debugging PHP code.
11+
12+
Installation
13+
------------
14+
15+
.. code-block:: terminal
16+
17+
$ composer require symfony/error-handler
18+
19+
.. include:: /components/require_autoload.rst.inc
20+
21+
Usage
22+
-----
23+
24+
The ErrorHandler component provides several tools to help you debug PHP code.
25+
Enable all of them by calling this method::
26+
27+
use Symfony\Component\ErrorHandler\Debug;
28+
29+
Debug::enable();
30+
31+
The :method:`Symfony\\Component\\ErrorHandler\\Debug::enable` method registers an
32+
error handler, an exception handler and
33+
:ref:`a special class loader <component-debug-class-loader>`.
34+
35+
Read the following sections for more information about the different available
36+
tools.
37+
38+
.. caution::
39+
40+
You should never enable the debug tools, except for the error handler, in a
41+
production environment as they might disclose sensitive information to the user.
42+
43+
Handling PHP Errors and Exceptions
44+
----------------------------------
45+
46+
Enabling the Error Handler
47+
~~~~~~~~~~~~~~~~~~~~~~~~~~
48+
49+
The :class:`Symfony\\Component\\ErrorHandler\\ErrorHandler` class catches PHP
50+
errors and converts them to exceptions (of class :phpclass:`ErrorException` or
51+
:class:`Symfony\\Component\\ErrorHandler\\Exception\\FatalErrorException` for
52+
PHP fatal errors)::
53+
54+
use Symfony\Component\ErrorHandler\ErrorHandler;
55+
56+
ErrorHandler::register();
57+
58+
This error handler is enabled by default in the production environment when the
59+
application uses the FrameworkBundle because it generates better error logs.
60+
61+
Enabling the Exception Handler
62+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
63+
64+
The :class:`Symfony\\Component\\ErrorHandler\\ExceptionHandler` class catches
65+
uncaught PHP exceptions and converts them to a nice PHP response. It is useful
66+
in :ref:`debug mode <debug-mode>` to replace the default PHP/XDebug output with
67+
something prettier and more useful::
68+
69+
use Symfony\Component\ErrorHandler\ExceptionHandler;
70+
71+
ExceptionHandler::register();
72+
73+
.. note::
74+
75+
If the :doc:`HttpFoundation component </components/http_foundation>` is
76+
available, the handler uses a Symfony Response object; if not, it falls
77+
back to a regular PHP response.
78+
79+
Catches PHP errors and turn them into exceptions
80+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
81+
82+
Most PHP core functions were written before exception handling was introduced to the
83+
language and most of this functions do not throw an exception on failure. Instead,
84+
they return ``false`` in case of error.
85+
86+
Let's take the following code example::
87+
88+
$data = json_decode(file_get_contents($filename), true);
89+
$data['read_at'] = date($datetimeFormat);
90+
file_put_contents($filename, json_encode($data));
91+
92+
All these functions ``file_get_contents``, ``json_decode``, ``date``, ``json_encode``
93+
and ``file_put_contents`` will return ``false`` or ``null`` on error, having to
94+
deal with those failures manually::
95+
96+
$content = @file_get_contents($filename);
97+
if (false === $content) {
98+
throw new \RuntimeException('Could not load file.');
99+
}
100+
$data = @json_decode($content, true);
101+
if (null === $data) {
102+
throw new \RuntimeException('File does not contain valid JSON.');
103+
}
104+
$datetime = @date($datetimeFormat);
105+
if (false === $datetime) {
106+
throw new \RuntimeException('Invalid datetime format.');
107+
}
108+
// ...
109+
110+
.. note::
111+
112+
Since PHP 7.3 `json_decode`_ function will accept a new ``JSON_THROW_ON_ERROR`` option
113+
that will let ``json_decode`` throw an exception instead of returning ``null`` on error.
114+
However, it is not enabled by default, so you will need to explicitly configure it.
115+
116+
To simplify this behavior the :class:`Symfony\\Component\\ErrorHandler\\ErrorHandler` class
117+
provides a :method:`Symfony\\Component\\ErrorHandler\\ErrorHandler::call` method that will
118+
automatically throw an exception when such a failure occurs. This method will accept a ``callable``
119+
parameter and then the arguments needed to call it, returning back the result::
120+
121+
$content = ErrorHandler::call('file_get_contents', $filename);
122+
123+
This way, you could use a ``\Closure`` function to wrap a portion of code and be sure that it
124+
breaks even if the `@-silencing operator`_ is used::
125+
126+
$data = ErrorHandler::call(static function () use ($filename, $datetimeFormat) {
127+
$data = json_decode(file_get_contents($filename), true);
128+
$data['read_at'] = date($datetimeFormat);
129+
file_put_contents($filename, json_encode($data));
130+
131+
return $data;
132+
});
133+
134+
.. _component-debug-class-loader:
135+
136+
Debugging a Class Loader
137+
------------------------
138+
139+
The :class:`Symfony\\Component\\ErrorHandler\\DebugClassLoader` attempts to
140+
throw more helpful exceptions when a class isn't found by the registered
141+
autoloaders. All autoloaders that implement a ``findFile()`` method are replaced
142+
with a ``DebugClassLoader`` wrapper.
143+
144+
Using the ``DebugClassLoader`` is done by calling its static
145+
:method:`Symfony\\Component\\ErrorHandler\\DebugClassLoader::enable` method::
146+
147+
use Symfony\Component\ErrorHandler\DebugClassLoader;
148+
149+
DebugClassLoader::enable();
150+
151+
.. _`@-silencing operator`: https://php.net/manual/en/function.json-decode.php
152+
.. _`json_decode`: https://php.net/manual/en/language.operators.errorcontrol.php

components/error_renderer.rst

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
.. index::
2+
single: Error
3+
single: Exception
4+
single: Components; ErrorRenderer
5+
6+
The ErrorRenderer Component
7+
===========================
8+
9+
The ErrorRenderer component converts PHP errors and exceptions into other
10+
formats such as JSON and HTML and renders them.
11+
12+
Installation
13+
------------
14+
15+
.. code-block:: terminal
16+
17+
$ composer require symfony/error-renderer
18+
19+
.. include:: /components/require_autoload.rst.inc
20+
21+
Usage
22+
-----
23+
24+
The ErrorRenderer component provides several renderers to convert PHP errors and
25+
exceptions into other formats such as JSON and HTML easier to debug when working
26+
with HTTP applications::
27+
28+
use Symfony\Component\ErrorRenderer\ErrorRenderer;
29+
use Symfony\Component\ErrorRenderer\ErrorRenderer\HtmlErrorRenderer;
30+
use Symfony\Component\ErrorRenderer\ErrorRenderer\JsonErrorRenderer;
31+
use Symfony\Component\ErrorRenderer\Exception\FlattenException;
32+
use Symfony\Component\HttpFoundation\Response;
33+
34+
$renderers = [
35+
new HtmlErrorRenderer(),
36+
new JsonErrorRenderer(),
37+
// ...
38+
];
39+
$errorRenderer = new ErrorRenderer($renderers);
40+
41+
try {
42+
// ...
43+
} catch (\Throwable $e) {
44+
$e = FlattenException::createFromThrowable($e);
45+
46+
return new Response($errorRenderer->render($e, 'json'), 500, ['Content-Type' => 'application/json']);
47+
}
48+
49+
Built-in Error Renderers
50+
~~~~~~~~~~~~~~~~~~~~~~~~
51+
52+
This component provides error renderers for the most common needs:
53+
54+
* :class:`Symfony\\Component\\ErrorRenderer\\ErrorRenderer\\HtmlErrorRenderer`
55+
renders errors in HTML format;
56+
* :class:`Symfony\\Component\\ErrorRenderer\\ErrorRenderer\\JsonErrorRenderer`
57+
renders errors in JSON format and it's compliant with the `RFC 7807`_ standard;
58+
* :class:`Symfony\\Component\\ErrorRenderer\\ErrorRenderer\\XmlErrorRenderer`
59+
renders errors in XML and Atom formats. It's compliant with the `RFC 7807`_
60+
standard;
61+
* :class:`Symfony\\Component\\ErrorRenderer\\ErrorRenderer\\TxtErrorRenderer`
62+
renders errors in plain text format.
63+
64+
Adding a Custom Error Renderer
65+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
66+
67+
Error renderers are PHP classes that implement the
68+
:class:`Symfony\\Component\\ErrorRenderer\\ErrorRenderer\\ErrorRendererInterface`.
69+
For example, if you need to render errors in `JSON-LD format`_, create this
70+
class anywhere in your project::
71+
72+
namespace App\ErrorRenderer;
73+
74+
use Symfony\Component\ErrorRenderer\ErrorRenderer\ErrorRendererInterface;
75+
use Symfony\Component\ErrorRenderer\Exception\FlattenException;
76+
77+
class JsonLdErrorRenderer implements ErrorRendererInterface
78+
{
79+
private $debug;
80+
81+
public function __construct(bool $debug = true)
82+
{
83+
$this->debug = $debug;
84+
}
85+
86+
public static function getFormat(): string
87+
{
88+
return 'jsonld';
89+
}
90+
91+
public function render(FlattenException $exception): string
92+
{
93+
$content = [
94+
'@id' => 'https://example.com',
95+
'@type' => 'error',
96+
'@context' => [
97+
'title' => $exception->getTitle(),
98+
'code' => $exception->getStatusCode(),
99+
'message' => $exception->getMessage(),
100+
],
101+
];
102+
103+
if ($this->debug) {
104+
$content['@context']['exceptions'] = $exception->toArray();
105+
}
106+
107+
return (string) json_encode($content);
108+
}
109+
}
110+
111+
.. tip::
112+
113+
If the ``getFormat()`` method of your error renderer matches one of formats
114+
supported by the built-in renderers, the built-in renderer is replaced by
115+
your custom renderer.
116+
117+
To enable the new error renderer in the application,
118+
:ref:`register it as a service <service-container-creating-service>` and
119+
:doc:`tag it </service_container/tags>` with the ``error_renderer.renderer``
120+
tag.
121+
122+
.. configuration-block::
123+
124+
.. code-block:: yaml
125+
126+
# config/services.yaml
127+
services:
128+
App\ErrorRenderer\JsonLdErrorRenderer:
129+
arguments: ['%kernel.debug%']
130+
tags: ['error_renderer.renderer']
131+
132+
.. code-block:: xml
133+
134+
<!-- config/services.xml -->
135+
<?xml version="1.0" encoding="UTF-8" ?>
136+
<container xmlns="http://symfony.com/schema/dic/services"
137+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
138+
xsi:schemaLocation="http://symfony.com/schema/dic/services
139+
https://symfony.com/schema/dic/services/services-1.0.xsd">
140+
141+
<services>
142+
<service id="App\ErrorRenderer\JsonLdErrorRenderer">
143+
<argument>%kernel.debug%</argument>
144+
<tag name="error_renderer.renderer"/>
145+
</service>
146+
</services>
147+
</container>
148+
149+
.. code-block:: php
150+
151+
// config/services.php
152+
use App\ErrorRenderer\JsonLdErrorRenderer;
153+
154+
$container->register(JsonLdErrorRenderer::class)
155+
->setArguments([$container->getParameter('kernel.debug')]);
156+
->addTag('error_renderer.renderer');
157+
158+
.. _`RFC 7807`: https://tools.ietf.org/html/rfc7807
159+
.. _`JSON-LD format`: https://en.wikipedia.org/wiki/JSON-LD

components/http_kernel.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -554,7 +554,7 @@ below for more details).
554554
The listener has several goals:
555555

556556
1) The thrown exception is converted into a
557-
:class:`Symfony\\Component\\Debug\\Exception\\FlattenException`
557+
:class:`Symfony\\Component\\ErrorRenderer\\Exception\\FlattenException`
558558
object, which contains all the information about the request, but which
559559
can be printed and serialized.
560560

0 commit comments

Comments
 (0)