From b2a1a9b878f1a0fbb62211c9d218cc2d5a5781f4 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 2 Jul 2019 15:06:46 +0200 Subject: [PATCH 1/8] Documented the ErrorCatcher component --- components/debug.rst | 44 +--- components/error_catcher.rst | 205 ++++++++++++++++++ .../front_controllers_and_kernel.rst | 2 + .../http_kernel_httpkernel_class.rst | 4 +- 4 files changed, 214 insertions(+), 41 deletions(-) create mode 100644 components/error_catcher.rst diff --git a/components/debug.rst b/components/debug.rst index 6f116e25af6..b8da5f31d4e 100644 --- a/components/debug.rst +++ b/components/debug.rst @@ -12,7 +12,7 @@ Installation .. code-block:: terminal - $ composer require symfony/debug + $ composer require --dev symfony/debug .. include:: /components/require_autoload.rst.inc @@ -26,50 +26,16 @@ Enable all of them by calling this method:: Debug::enable(); -The :method:`Symfony\\Component\\Debug\\Debug::enable` method registers an -error handler, an exception handler and -:ref:`a special class loader `. - -Read the following sections for more information about the different available -tools. - .. caution:: You should never enable the debug tools, except for the error handler, in a production environment as they might disclose sensitive information to the user. -Enabling the Error Handler --------------------------- - -The :class:`Symfony\\Component\\Debug\\ErrorHandler` class catches PHP errors -and converts them to exceptions (of class :phpclass:`ErrorException` or -:class:`Symfony\\Component\\Debug\\Exception\\FatalErrorException` for PHP -fatal errors):: - - use Symfony\Component\Debug\ErrorHandler; - - ErrorHandler::register(); - -This error handler is enabled by default in the production environment when the -application uses the FrameworkBundle because it generates better error logs. - -Enabling the Exception Handler ------------------------------- - -The :class:`Symfony\\Component\\Debug\\ExceptionHandler` class catches -uncaught PHP exceptions and converts them to a nice PHP response. It is useful -in debug mode to replace the default PHP/XDebug output with something prettier -and more useful:: - - use Symfony\Component\Debug\ExceptionHandler; - - ExceptionHandler::register(); - -.. note:: +.. deprecated:: 4.4 - If the :doc:`HttpFoundation component ` is - available, the handler uses a Symfony Response object; if not, it falls - back to a regular PHP response. + In Symfony versions before 4.4, this component also provided error and + exception handlers. In Symfony 4.4 they were deprecated in favor of their + equivalent handlers included in the new :doc:`ErrorCatcher component `. .. _component-debug-class-loader: diff --git a/components/error_catcher.rst b/components/error_catcher.rst new file mode 100644 index 00000000000..a6aa7abd30e --- /dev/null +++ b/components/error_catcher.rst @@ -0,0 +1,205 @@ +.. index:: + single: Error + single: Exception + single: Components; ErrorCatcher + +The ErrorCatcher Component +========================== + + The ErrorCatcher component converts PHP errors and exceptions into other + formats such as JSON and HTML and renders them. + +Installation +------------ + +.. code-block:: terminal + + $ composer require symfony/error-catcher + +.. include:: /components/require_autoload.rst.inc + +Usage +----- + +The ErrorCatcher component provides several handlers and renderers to convert +PHP errors and exceptions into other formats easier to debug when working with +HTTP applications. + +.. TODO: how are these handlers enabled in the app? (Previously: Debug::enable()) + +Handling PHP Errors and Exceptions +---------------------------------- + +Enabling the Error Handler +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :class:`Symfony\\Component\\ErrorCatcher\\ErrorHandler` class catches PHP +errors and converts them to exceptions (of class :phpclass:`ErrorException` or +:class:`Symfony\\Component\\ErrorCatcher\\Exception\\FatalErrorException` for +PHP fatal errors):: + + use Symfony\Component\ErrorCatcher\ErrorHandler; + + ErrorHandler::register(); + +This error handler is enabled by default in the production environment when the +application uses the FrameworkBundle because it generates better error logs. + +Enabling the Exception Handler +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :class:`Symfony\\Component\\ErrorCatcher\\ExceptionHandler` class catches +uncaught PHP exceptions and converts them to a nice PHP response. It is useful +in :ref:`debug mode ` to replace the default PHP/XDebug output with +something prettier and more useful:: + + use Symfony\Component\ErrorCatcher\ExceptionHandler; + + ExceptionHandler::register(); + +.. note:: + + If the :doc:`HttpFoundation component ` is + available, the handler uses a Symfony Response object; if not, it falls + back to a regular PHP response. + +Rendering PHP Errors and Exceptions +----------------------------------- + +Another feature provided by this component are the "error renderers", which +converts PHP errors and exceptions into other formats such as JSON and HTML:: + + use Symfony\Component\ErrorHandler\ErrorRenderer\ErrorRenderer; + use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer; + use Symfony\Component\ErrorHandler\ErrorRenderer\JsonErrorRenderer; + + $renderers = [ + new HtmlErrorRenderer(), + new JsonErrorRenderer(), + // ... + ]; + $errorRenderer = new ErrorRenderer($renderers); + + /** @var Symfony\Component\ErrorHandler\Exception\FlattenException */ + $exception = ...; + /** @var Symfony\Component\HttpFoundation\Request */ + $request = ...; + + return new Response( + $errorRenderer->render($exception, $request->getRequestFormat()), + $exception->getStatusCode(), + $exception->getHeaders() + ); + +Built-in Error Renderers +~~~~~~~~~~~~~~~~~~~~~~~~ + +This component provides error renderers for the most common needs: + + * :class:`Symfony\\Component\\ErrorHandler\\ErrorRenderer\\HtmlErrorRenderer` + renders errors in HTML format; + * :class:`Symfony\\Component\\ErrorHandler\\ErrorRenderer\\JsonErrorRenderer` + renders errors in JsonErrorRenderer format and it's compliant with the + `RFC 7807`_ standard; + * :class:`Symfony\\Component\\ErrorHandler\\ErrorRenderer\\XmlErrorRenderer` + renders errors in XML and Atom formats. It's compliant with the `RFC 7807`_ + standard; + * :class:`Symfony\\Component\\ErrorHandler\\ErrorRenderer\\TxtErrorRenderer` + renders errors in regular text format. + +Adding a Custom Error Renderer +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Error renderers are PHP classes that implement the +:class:`Symfony\\Component\\ErrorHandler\\ErrorRenderer\\ErrorRendererInterface`. +For example, if you need to render errors in `JSON-LD format`_, create this +class anywhere in your project:: + + namespace App\ErrorHandler\ErrorRenderer; + + use Symfony\Component\ErrorHandler\ErrorRenderer\ErrorRendererInterface; + use Symfony\Component\ErrorHandler\Exception\FlattenException; + + class JsonLdErrorRenderer implements ErrorRendererInterface + { + private $debug; + + public static function getFormat(): string + { + return 'jsonld'; + } + + public function __construct(bool $debug = true) + { + $this->debug = $debug; + } + + public function render(FlattenException $exception): string + { + $content = [ + '@id' => 'https://example.com', + '@type' => 'error', + '@context' => [ + 'title' => $exception->getTitle(), + 'code' => $exception->getStatusCode(), + 'message' => $exception->getMessage(), + ], + ]; + + if ($this->debug) { + $content['@context']['exceptions'] = $exception->toArray(); + } + + return (string) json_encode($content); + } + } + +.. tip:: + + If the ``getformat()`` method of your error renderer matches one of formats + supported by the built-in renderers, the built-in renderer is replaced by + your custom renderer. + +To enable the new error renderer in the application, +:ref:`register it as a service ` and +:doc:`tag it ` with the ``error_handler.renderer`` +tag. + +.. configuration-block:: + + .. code-block:: yaml + + # config/services.yaml + services: + App\ErrorHandler\ErrorRenderer\JsonLdErrorRenderer: + arguments: ['%kernel.debug%'] + tags: ['error_handler.renderer'] + + .. code-block:: xml + + + + + + + + true + + + + + + .. code-block:: php + + // config/services.php + use App\ErrorHandler\ErrorRenderer\JsonLdErrorRenderer; + + $container->register(JsonLdErrorRenderer::class) + ->setArguments([true]); + ->addTag('error_handler.renderer'); + +.. _`RFC 7807`: https://tools.ietf.org/html/rfc7807 +.. _`JSON-LD format`: https://en.wikipedia.org/wiki/JSON-LD diff --git a/configuration/front_controllers_and_kernel.rst b/configuration/front_controllers_and_kernel.rst index d986d7471b7..bdeac5ed93d 100644 --- a/configuration/front_controllers_and_kernel.rst +++ b/configuration/front_controllers_and_kernel.rst @@ -123,6 +123,8 @@ new kernel. .. index:: single: Configuration; Debug mode +.. _debug-mode: + Debug Mode ~~~~~~~~~~ diff --git a/create_framework/http_kernel_httpkernel_class.rst b/create_framework/http_kernel_httpkernel_class.rst index f9f8f16932f..fc4a1149c13 100644 --- a/create_framework/http_kernel_httpkernel_class.rst +++ b/create_framework/http_kernel_httpkernel_class.rst @@ -69,7 +69,7 @@ Our code is now much more concise and surprisingly more robust and more powerful than ever. For instance, use the built-in ``ExceptionListener`` to make your error management configurable:: - $errorHandler = function (Symfony\Component\Debug\Exception\FlattenException $exception) { + $errorHandler = function (Symfony\Component\ErrorCatcher\Exception\FlattenException $exception) { $msg = 'Something went wrong! ('.$exception->getMessage().')'; return new Response($msg, $exception->getStatusCode()); @@ -91,7 +91,7 @@ The error controller reads as follows:: // example.com/src/Calendar/Controller/ErrorController.php namespace Calendar\Controller; - use Symfony\Component\Debug\Exception\FlattenException; + use Symfony\Component\ErrorCatcher\Exception\FlattenException; use Symfony\Component\HttpFoundation\Response; class ErrorController From 4e333c17b9fad553da1d11f6539fa8e4a1f851e9 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 3 Jul 2019 10:35:19 +0200 Subject: [PATCH 2/8] Fixes --- components/error_catcher.rst | 47 ++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/components/error_catcher.rst b/components/error_catcher.rst index a6aa7abd30e..85f0681fa3d 100644 --- a/components/error_catcher.rst +++ b/components/error_catcher.rst @@ -69,24 +69,24 @@ Rendering PHP Errors and Exceptions Another feature provided by this component are the "error renderers", which converts PHP errors and exceptions into other formats such as JSON and HTML:: - use Symfony\Component\ErrorHandler\ErrorRenderer\ErrorRenderer; - use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer; - use Symfony\Component\ErrorHandler\ErrorRenderer\JsonErrorRenderer; + use Symfony\Component\ErrorCatcher\ErrorRenderer\ErrorRenderer; + use Symfony\Component\ErrorCatcher\ErrorRenderer\HtmlErrorRenderer; + use Symfony\Component\ErrorCatcher\ErrorRenderer\JsonErrorRenderer; $renderers = [ new HtmlErrorRenderer(), new JsonErrorRenderer(), // ... ]; - $errorRenderer = new ErrorRenderer($renderers); + $errorFormatter = new ErrorFormatter($renderers); - /** @var Symfony\Component\ErrorHandler\Exception\FlattenException */ + /** @var Symfony\Component\ErrorCatcher\Exception\FlattenException */ $exception = ...; /** @var Symfony\Component\HttpFoundation\Request */ $request = ...; return new Response( - $errorRenderer->render($exception, $request->getRequestFormat()), + $errorFormatter->render($exception, $request->getRequestFormat()), $exception->getStatusCode(), $exception->getHeaders() ); @@ -96,29 +96,28 @@ Built-in Error Renderers This component provides error renderers for the most common needs: - * :class:`Symfony\\Component\\ErrorHandler\\ErrorRenderer\\HtmlErrorRenderer` + * :class:`Symfony\\Component\\ErrorCatcher\\ErrorRenderer\\HtmlErrorRenderer` renders errors in HTML format; - * :class:`Symfony\\Component\\ErrorHandler\\ErrorRenderer\\JsonErrorRenderer` - renders errors in JsonErrorRenderer format and it's compliant with the - `RFC 7807`_ standard; - * :class:`Symfony\\Component\\ErrorHandler\\ErrorRenderer\\XmlErrorRenderer` + * :class:`Symfony\\Component\\ErrorCatcher\\ErrorRenderer\\JsonErrorRenderer` + renders errors in JSON format and it's compliant with the `RFC 7807`_ standard; + * :class:`Symfony\\Component\\ErrorCatcher\\ErrorRenderer\\XmlErrorRenderer` renders errors in XML and Atom formats. It's compliant with the `RFC 7807`_ standard; - * :class:`Symfony\\Component\\ErrorHandler\\ErrorRenderer\\TxtErrorRenderer` - renders errors in regular text format. + * :class:`Symfony\\Component\\ErrorCatcher\\ErrorRenderer\\TxtErrorRenderer` + renders errors in plain text format. Adding a Custom Error Renderer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Error renderers are PHP classes that implement the -:class:`Symfony\\Component\\ErrorHandler\\ErrorRenderer\\ErrorRendererInterface`. +:class:`Symfony\\Component\\ErrorCatcher\\ErrorRenderer\\ErrorRendererInterface`. For example, if you need to render errors in `JSON-LD format`_, create this class anywhere in your project:: - namespace App\ErrorHandler\ErrorRenderer; + namespace App\ErrorCatcher; - use Symfony\Component\ErrorHandler\ErrorRenderer\ErrorRendererInterface; - use Symfony\Component\ErrorHandler\Exception\FlattenException; + use Symfony\Component\ErrorCatcher\ErrorRenderer\ErrorRendererInterface; + use Symfony\Component\ErrorCatcher\Exception\FlattenException; class JsonLdErrorRenderer implements ErrorRendererInterface { @@ -162,7 +161,7 @@ class anywhere in your project:: To enable the new error renderer in the application, :ref:`register it as a service ` and -:doc:`tag it ` with the ``error_handler.renderer`` +:doc:`tag it ` with the ``error_catcher.renderer`` tag. .. configuration-block:: @@ -171,9 +170,9 @@ tag. # config/services.yaml services: - App\ErrorHandler\ErrorRenderer\JsonLdErrorRenderer: + App\ErrorCatcher\JsonLdErrorRenderer: arguments: ['%kernel.debug%'] - tags: ['error_handler.renderer'] + tags: ['error_catcher.renderer'] .. code-block:: xml @@ -185,9 +184,9 @@ tag. https://symfony.com/schema/dic/services/services-1.0.xsd"> - + true - + @@ -195,11 +194,11 @@ tag. .. code-block:: php // config/services.php - use App\ErrorHandler\ErrorRenderer\JsonLdErrorRenderer; + use App\ErrorCatcher\JsonLdErrorRenderer; $container->register(JsonLdErrorRenderer::class) ->setArguments([true]); - ->addTag('error_handler.renderer'); + ->addTag('error_catcher.renderer'); .. _`RFC 7807`: https://tools.ietf.org/html/rfc7807 .. _`JSON-LD format`: https://en.wikipedia.org/wiki/JSON-LD From b600b3c8c8b880b6a80d86c43ba6eeab91a3af96 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 12 Jul 2019 10:35:47 +0200 Subject: [PATCH 3/8] Renamed ErrorCatcher as ErrorRenderer --- .../{error_catcher.rst => error_renderer.rst} | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) rename components/{error_catcher.rst => error_renderer.rst} (75%) diff --git a/components/error_catcher.rst b/components/error_renderer.rst similarity index 75% rename from components/error_catcher.rst rename to components/error_renderer.rst index 85f0681fa3d..5c14fdac0f5 100644 --- a/components/error_catcher.rst +++ b/components/error_renderer.rst @@ -1,12 +1,12 @@ .. index:: single: Error single: Exception - single: Components; ErrorCatcher + single: Components; ErrorRenderer -The ErrorCatcher Component -========================== +The ErrorRenderer Component +=========================== - The ErrorCatcher component converts PHP errors and exceptions into other + The ErrorRenderer component converts PHP errors and exceptions into other formats such as JSON and HTML and renders them. Installation @@ -14,14 +14,14 @@ Installation .. code-block:: terminal - $ composer require symfony/error-catcher + $ composer require symfony/error-renderer .. include:: /components/require_autoload.rst.inc Usage ----- -The ErrorCatcher component provides several handlers and renderers to convert +The ErrorRenderer component provides several handlers and renderers to convert PHP errors and exceptions into other formats easier to debug when working with HTTP applications. @@ -33,12 +33,12 @@ Handling PHP Errors and Exceptions Enabling the Error Handler ~~~~~~~~~~~~~~~~~~~~~~~~~~ -The :class:`Symfony\\Component\\ErrorCatcher\\ErrorHandler` class catches PHP +The :class:`Symfony\\Component\\ErrorRenderer\\ErrorHandler` class catches PHP errors and converts them to exceptions (of class :phpclass:`ErrorException` or -:class:`Symfony\\Component\\ErrorCatcher\\Exception\\FatalErrorException` for +:class:`Symfony\\Component\\ErrorRenderer\\Exception\\FatalErrorException` for PHP fatal errors):: - use Symfony\Component\ErrorCatcher\ErrorHandler; + use Symfony\Component\ErrorRenderer\ErrorHandler; ErrorHandler::register(); @@ -48,12 +48,12 @@ application uses the FrameworkBundle because it generates better error logs. Enabling the Exception Handler ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The :class:`Symfony\\Component\\ErrorCatcher\\ExceptionHandler` class catches +The :class:`Symfony\\Component\\ErrorRenderer\\ExceptionHandler` class catches uncaught PHP exceptions and converts them to a nice PHP response. It is useful in :ref:`debug mode ` to replace the default PHP/XDebug output with something prettier and more useful:: - use Symfony\Component\ErrorCatcher\ExceptionHandler; + use Symfony\Component\ErrorRenderer\ExceptionHandler; ExceptionHandler::register(); @@ -69,9 +69,9 @@ Rendering PHP Errors and Exceptions Another feature provided by this component are the "error renderers", which converts PHP errors and exceptions into other formats such as JSON and HTML:: - use Symfony\Component\ErrorCatcher\ErrorRenderer\ErrorRenderer; - use Symfony\Component\ErrorCatcher\ErrorRenderer\HtmlErrorRenderer; - use Symfony\Component\ErrorCatcher\ErrorRenderer\JsonErrorRenderer; + use Symfony\Component\ErrorRenderer\ErrorRenderer\ErrorRenderer; + use Symfony\Component\ErrorRenderer\ErrorRenderer\HtmlErrorRenderer; + use Symfony\Component\ErrorRenderer\ErrorRenderer\JsonErrorRenderer; $renderers = [ new HtmlErrorRenderer(), @@ -80,7 +80,7 @@ converts PHP errors and exceptions into other formats such as JSON and HTML:: ]; $errorFormatter = new ErrorFormatter($renderers); - /** @var Symfony\Component\ErrorCatcher\Exception\FlattenException */ + /** @var Symfony\Component\ErrorRenderer\Exception\FlattenException */ $exception = ...; /** @var Symfony\Component\HttpFoundation\Request */ $request = ...; @@ -96,28 +96,28 @@ Built-in Error Renderers This component provides error renderers for the most common needs: - * :class:`Symfony\\Component\\ErrorCatcher\\ErrorRenderer\\HtmlErrorRenderer` + * :class:`Symfony\\Component\\ErrorRenderer\\ErrorRenderer\\HtmlErrorRenderer` renders errors in HTML format; - * :class:`Symfony\\Component\\ErrorCatcher\\ErrorRenderer\\JsonErrorRenderer` + * :class:`Symfony\\Component\\ErrorRenderer\\ErrorRenderer\\JsonErrorRenderer` renders errors in JSON format and it's compliant with the `RFC 7807`_ standard; - * :class:`Symfony\\Component\\ErrorCatcher\\ErrorRenderer\\XmlErrorRenderer` + * :class:`Symfony\\Component\\ErrorRenderer\\ErrorRenderer\\XmlErrorRenderer` renders errors in XML and Atom formats. It's compliant with the `RFC 7807`_ standard; - * :class:`Symfony\\Component\\ErrorCatcher\\ErrorRenderer\\TxtErrorRenderer` + * :class:`Symfony\\Component\\ErrorRenderer\\ErrorRenderer\\TxtErrorRenderer` renders errors in plain text format. Adding a Custom Error Renderer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Error renderers are PHP classes that implement the -:class:`Symfony\\Component\\ErrorCatcher\\ErrorRenderer\\ErrorRendererInterface`. +:class:`Symfony\\Component\\ErrorRenderer\\ErrorRenderer\\ErrorRendererInterface`. For example, if you need to render errors in `JSON-LD format`_, create this class anywhere in your project:: - namespace App\ErrorCatcher; + namespace App\ErrorRenderer; - use Symfony\Component\ErrorCatcher\ErrorRenderer\ErrorRendererInterface; - use Symfony\Component\ErrorCatcher\Exception\FlattenException; + use Symfony\Component\ErrorRenderer\ErrorRenderer\ErrorRendererInterface; + use Symfony\Component\ErrorRenderer\Exception\FlattenException; class JsonLdErrorRenderer implements ErrorRendererInterface { @@ -170,7 +170,7 @@ tag. # config/services.yaml services: - App\ErrorCatcher\JsonLdErrorRenderer: + App\ErrorRenderer\JsonLdErrorRenderer: arguments: ['%kernel.debug%'] tags: ['error_catcher.renderer'] @@ -184,7 +184,7 @@ tag. https://symfony.com/schema/dic/services/services-1.0.xsd"> - + true @@ -194,7 +194,7 @@ tag. .. code-block:: php // config/services.php - use App\ErrorCatcher\JsonLdErrorRenderer; + use App\ErrorRenderer\JsonLdErrorRenderer; $container->register(JsonLdErrorRenderer::class) ->setArguments([true]); From b0723efba53b3484d373495e8becc53986d6bdeb Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 12 Jul 2019 10:36:36 +0200 Subject: [PATCH 4/8] Fixed a method name --- components/error_renderer.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/error_renderer.rst b/components/error_renderer.rst index 5c14fdac0f5..89a7e99a4b5 100644 --- a/components/error_renderer.rst +++ b/components/error_renderer.rst @@ -155,7 +155,7 @@ class anywhere in your project:: .. tip:: - If the ``getformat()`` method of your error renderer matches one of formats + If the ``getFormat()`` method of your error renderer matches one of formats supported by the built-in renderers, the built-in renderer is replaced by your custom renderer. From 5136a17136db054af3919c2ab588635a29c0a536 Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Fri, 16 Aug 2019 10:00:33 -0400 Subject: [PATCH 5/8] Update with latest changes: ErrorRenderer and ErrorHandler components --- components/debug.rst | 19 +--- components/error_handler.rst | 94 +++++++++++++++++++ components/error_renderer.rst | 72 +++----------- components/http_kernel.rst | 2 +- controller/error_pages.rst | 2 +- .../http_kernel_httpkernel_class.rst | 4 +- 6 files changed, 113 insertions(+), 80 deletions(-) create mode 100644 components/error_handler.rst diff --git a/components/debug.rst b/components/debug.rst index b8da5f31d4e..ceeaf505cce 100644 --- a/components/debug.rst +++ b/components/debug.rst @@ -35,21 +35,4 @@ Enable all of them by calling this method:: In Symfony versions before 4.4, this component also provided error and exception handlers. In Symfony 4.4 they were deprecated in favor of their - equivalent handlers included in the new :doc:`ErrorCatcher component `. - -.. _component-debug-class-loader: - -Debugging a Class Loader ------------------------- - -The :class:`Symfony\\Component\\Debug\\DebugClassLoader` attempts to -throw more helpful exceptions when a class isn't found by the registered -autoloaders. All autoloaders that implement a ``findFile()`` method are replaced -with a ``DebugClassLoader`` wrapper. - -Using the ``DebugClassLoader`` is done by calling its static -:method:`Symfony\\Component\\Debug\\DebugClassLoader::enable` method:: - - use Symfony\Component\Debug\DebugClassLoader; - - DebugClassLoader::enable(); + equivalent handlers included in the new :doc:`ErrorHandler component `. diff --git a/components/error_handler.rst b/components/error_handler.rst new file mode 100644 index 00000000000..59240953a25 --- /dev/null +++ b/components/error_handler.rst @@ -0,0 +1,94 @@ +.. index:: + single: Debug + single: Error + single: Exception + single: Components; ErrorHandler + +The ErrorHandler Component +========================== + + The ErrorHandler component provides tools to manage errors and ease debugging PHP code. + +Installation +------------ + +.. code-block:: terminal + + $ composer require symfony/error-handler + +.. include:: /components/require_autoload.rst.inc + +Usage +----- + +The ErrorHandler component provides several tools to help you debug PHP code. +Enable all of them by calling this method:: + + use Symfony\Component\ErrorHandler\Debug; + + Debug::enable(); + +The :method:`Symfony\\Component\\ErrorHandler\\Debug::enable` method registers an +error handler, an exception handler and +:ref:`a special class loader `. + +Read the following sections for more information about the different available +tools. + +.. caution:: + + You should never enable the debug tools, except for the error handler, in a + production environment as they might disclose sensitive information to the user. + +Handling PHP Errors and Exceptions +---------------------------------- + +Enabling the Error Handler +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :class:`Symfony\\Component\\ErrorHandler\\ErrorHandler` class catches PHP +errors and converts them to exceptions (of class :phpclass:`ErrorException` or +:class:`Symfony\\Component\\ErrorHandler\\Exception\\FatalErrorException` for +PHP fatal errors):: + + use Symfony\Component\ErrorHandler\ErrorHandler; + + ErrorHandler::register(); + +This error handler is enabled by default in the production environment when the +application uses the FrameworkBundle because it generates better error logs. + +Enabling the Exception Handler +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :class:`Symfony\\Component\\ErrorHandler\\ExceptionHandler` class catches +uncaught PHP exceptions and converts them to a nice PHP response. It is useful +in :ref:`debug mode ` to replace the default PHP/XDebug output with +something prettier and more useful:: + + use Symfony\Component\ErrorHandler\ExceptionHandler; + + ExceptionHandler::register(); + +.. note:: + + If the :doc:`HttpFoundation component ` is + available, the handler uses a Symfony Response object; if not, it falls + back to a regular PHP response. + +.. _component-debug-class-loader: + +Debugging a Class Loader +------------------------ + +The :class:`Symfony\\Component\\ErrorHandler\\DebugClassLoader` attempts to +throw more helpful exceptions when a class isn't found by the registered +autoloaders. All autoloaders that implement a ``findFile()`` method are replaced +with a ``DebugClassLoader`` wrapper. + +Using the ``DebugClassLoader`` is done by calling its static +:method:`Symfony\\Component\\ErrorHandler\\DebugClassLoader::enable` method:: + + use Symfony\Component\ErrorHandler\DebugClassLoader; + + DebugClassLoader::enable(); diff --git a/components/error_renderer.rst b/components/error_renderer.rst index 89a7e99a4b5..001364aa622 100644 --- a/components/error_renderer.rst +++ b/components/error_renderer.rst @@ -21,55 +21,11 @@ Installation Usage ----- -The ErrorRenderer component provides several handlers and renderers to convert -PHP errors and exceptions into other formats easier to debug when working with -HTTP applications. +The ErrorRenderer component provides several renderers to convert PHP errors and +exceptions into other formats such as JSON and HTML easier to debug when working +with HTTP applications:: -.. TODO: how are these handlers enabled in the app? (Previously: Debug::enable()) - -Handling PHP Errors and Exceptions ----------------------------------- - -Enabling the Error Handler -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The :class:`Symfony\\Component\\ErrorRenderer\\ErrorHandler` class catches PHP -errors and converts them to exceptions (of class :phpclass:`ErrorException` or -:class:`Symfony\\Component\\ErrorRenderer\\Exception\\FatalErrorException` for -PHP fatal errors):: - - use Symfony\Component\ErrorRenderer\ErrorHandler; - - ErrorHandler::register(); - -This error handler is enabled by default in the production environment when the -application uses the FrameworkBundle because it generates better error logs. - -Enabling the Exception Handler -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The :class:`Symfony\\Component\\ErrorRenderer\\ExceptionHandler` class catches -uncaught PHP exceptions and converts them to a nice PHP response. It is useful -in :ref:`debug mode ` to replace the default PHP/XDebug output with -something prettier and more useful:: - - use Symfony\Component\ErrorRenderer\ExceptionHandler; - - ExceptionHandler::register(); - -.. note:: - - If the :doc:`HttpFoundation component ` is - available, the handler uses a Symfony Response object; if not, it falls - back to a regular PHP response. - -Rendering PHP Errors and Exceptions ------------------------------------ - -Another feature provided by this component are the "error renderers", which -converts PHP errors and exceptions into other formats such as JSON and HTML:: - - use Symfony\Component\ErrorRenderer\ErrorRenderer\ErrorRenderer; + use Symfony\Component\ErrorRenderer\ErrorRenderer; use Symfony\Component\ErrorRenderer\ErrorRenderer\HtmlErrorRenderer; use Symfony\Component\ErrorRenderer\ErrorRenderer\JsonErrorRenderer; @@ -78,7 +34,7 @@ converts PHP errors and exceptions into other formats such as JSON and HTML:: new JsonErrorRenderer(), // ... ]; - $errorFormatter = new ErrorFormatter($renderers); + $errorRenderer = new ErrorRenderer($renderers); /** @var Symfony\Component\ErrorRenderer\Exception\FlattenException */ $exception = ...; @@ -86,7 +42,7 @@ converts PHP errors and exceptions into other formats such as JSON and HTML:: $request = ...; return new Response( - $errorFormatter->render($exception, $request->getRequestFormat()), + $errorRenderer->render($exception, $request->getPreferredFormat()), $exception->getStatusCode(), $exception->getHeaders() ); @@ -123,14 +79,14 @@ class anywhere in your project:: { private $debug; - public static function getFormat(): string + public function __construct(bool $debug = true) { - return 'jsonld'; + $this->debug = $debug; } - public function __construct(bool $debug = true) + public static function getFormat(): string { - $this->debug = $debug; + return 'jsonld'; } public function render(FlattenException $exception): string @@ -161,7 +117,7 @@ class anywhere in your project:: To enable the new error renderer in the application, :ref:`register it as a service ` and -:doc:`tag it ` with the ``error_catcher.renderer`` +:doc:`tag it ` with the ``error_renderer.renderer`` tag. .. configuration-block:: @@ -172,7 +128,7 @@ tag. services: App\ErrorRenderer\JsonLdErrorRenderer: arguments: ['%kernel.debug%'] - tags: ['error_catcher.renderer'] + tags: ['error_renderer.renderer'] .. code-block:: xml @@ -186,7 +142,7 @@ tag. true - + @@ -198,7 +154,7 @@ tag. $container->register(JsonLdErrorRenderer::class) ->setArguments([true]); - ->addTag('error_catcher.renderer'); + ->addTag('error_renderer.renderer'); .. _`RFC 7807`: https://tools.ietf.org/html/rfc7807 .. _`JSON-LD format`: https://en.wikipedia.org/wiki/JSON-LD diff --git a/components/http_kernel.rst b/components/http_kernel.rst index 2b2ebe3b5fc..93da3f6156e 100644 --- a/components/http_kernel.rst +++ b/components/http_kernel.rst @@ -554,7 +554,7 @@ below for more details). The listener has several goals: 1) The thrown exception is converted into a - :class:`Symfony\\Component\\Debug\\Exception\\FlattenException` + :class:`Symfony\\Component\\ErrorRenderer\\Exception\\FlattenException` object, which contains all the information about the request, but which can be printed and serialized. diff --git a/controller/error_pages.rst b/controller/error_pages.rst index a4026b75a66..482ba6edd95 100644 --- a/controller/error_pages.rst +++ b/controller/error_pages.rst @@ -247,7 +247,7 @@ the request that will be dispatched to your controller. In addition, your contro will be passed two parameters: ``exception`` - A :class:`\\Symfony\\Component\\Debug\\Exception\\FlattenException` + A :class:`\\Symfony\\Component\\ErrorRenderer\\Exception\\FlattenException` instance created from the exception being handled. ``logger`` diff --git a/create_framework/http_kernel_httpkernel_class.rst b/create_framework/http_kernel_httpkernel_class.rst index fc4a1149c13..5845f4219dc 100644 --- a/create_framework/http_kernel_httpkernel_class.rst +++ b/create_framework/http_kernel_httpkernel_class.rst @@ -69,7 +69,7 @@ Our code is now much more concise and surprisingly more robust and more powerful than ever. For instance, use the built-in ``ExceptionListener`` to make your error management configurable:: - $errorHandler = function (Symfony\Component\ErrorCatcher\Exception\FlattenException $exception) { + $errorHandler = function (Symfony\Component\ErrorRenderer\Exception\FlattenException $exception) { $msg = 'Something went wrong! ('.$exception->getMessage().')'; return new Response($msg, $exception->getStatusCode()); @@ -91,7 +91,7 @@ The error controller reads as follows:: // example.com/src/Calendar/Controller/ErrorController.php namespace Calendar\Controller; - use Symfony\Component\ErrorCatcher\Exception\FlattenException; + use Symfony\Component\ErrorRenderer\Exception\FlattenException; use Symfony\Component\HttpFoundation\Response; class ErrorController From 5a025c9c037085a7cb3177ae97398386522b76fb Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Sat, 17 Aug 2019 10:00:51 -0400 Subject: [PATCH 6/8] fix example --- components/error_renderer.rst | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/components/error_renderer.rst b/components/error_renderer.rst index 001364aa622..acf379f8741 100644 --- a/components/error_renderer.rst +++ b/components/error_renderer.rst @@ -28,6 +28,8 @@ with HTTP applications:: use Symfony\Component\ErrorRenderer\ErrorRenderer; use Symfony\Component\ErrorRenderer\ErrorRenderer\HtmlErrorRenderer; use Symfony\Component\ErrorRenderer\ErrorRenderer\JsonErrorRenderer; + use Symfony\Component\ErrorRenderer\Exception\FlattenException; + use Symfony\Component\HttpFoundation\Response; $renderers = [ new HtmlErrorRenderer(), @@ -36,16 +38,13 @@ with HTTP applications:: ]; $errorRenderer = new ErrorRenderer($renderers); - /** @var Symfony\Component\ErrorRenderer\Exception\FlattenException */ - $exception = ...; - /** @var Symfony\Component\HttpFoundation\Request */ - $request = ...; + try { + // ... + } catch (\Throwable $e) { + $e = FlattenException::createFromThrowable($e); - return new Response( - $errorRenderer->render($exception, $request->getPreferredFormat()), - $exception->getStatusCode(), - $exception->getHeaders() - ); + return new Response($errorRenderer->render($e, 'json'), 500, ['Content-Type' => 'application/json']); + } Built-in Error Renderers ~~~~~~~~~~~~~~~~~~~~~~~~ From 3ea9817cd68b34c76b2ee1047c95dede54cc5a14 Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Sat, 17 Aug 2019 10:05:09 -0400 Subject: [PATCH 7/8] fix service definition --- components/error_renderer.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/error_renderer.rst b/components/error_renderer.rst index acf379f8741..c62fd39c117 100644 --- a/components/error_renderer.rst +++ b/components/error_renderer.rst @@ -140,7 +140,7 @@ tag. - true + %kernel.debug% @@ -152,7 +152,7 @@ tag. use App\ErrorRenderer\JsonLdErrorRenderer; $container->register(JsonLdErrorRenderer::class) - ->setArguments([true]); + ->setArguments([$container->getParameter('kernel.debug')]); ->addTag('error_renderer.renderer'); .. _`RFC 7807`: https://tools.ietf.org/html/rfc7807 From 8cc084f70eb5bbea234771fe990ea0a4415898ce Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Mon, 19 Aug 2019 15:48:12 -0400 Subject: [PATCH 8/8] documenting the ErrorHandler::call method --- components/error_handler.rst | 58 ++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/components/error_handler.rst b/components/error_handler.rst index 59240953a25..e394ece0f4f 100644 --- a/components/error_handler.rst +++ b/components/error_handler.rst @@ -76,6 +76,61 @@ something prettier and more useful:: available, the handler uses a Symfony Response object; if not, it falls back to a regular PHP response. +Catches PHP errors and turn them into exceptions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Most PHP core functions were written before exception handling was introduced to the +language and most of this functions do not throw an exception on failure. Instead, +they return ``false`` in case of error. + +Let's take the following code example:: + + $data = json_decode(file_get_contents($filename), true); + $data['read_at'] = date($datetimeFormat); + file_put_contents($filename, json_encode($data)); + +All these functions ``file_get_contents``, ``json_decode``, ``date``, ``json_encode`` +and ``file_put_contents`` will return ``false`` or ``null`` on error, having to +deal with those failures manually:: + + $content = @file_get_contents($filename); + if (false === $content) { + throw new \RuntimeException('Could not load file.'); + } + $data = @json_decode($content, true); + if (null === $data) { + throw new \RuntimeException('File does not contain valid JSON.'); + } + $datetime = @date($datetimeFormat); + if (false === $datetime) { + throw new \RuntimeException('Invalid datetime format.'); + } + // ... + +.. note:: + + Since PHP 7.3 `json_decode`_ function will accept a new ``JSON_THROW_ON_ERROR`` option + that will let ``json_decode`` throw an exception instead of returning ``null`` on error. + However, it is not enabled by default, so you will need to explicitly configure it. + +To simplify this behavior the :class:`Symfony\\Component\\ErrorHandler\\ErrorHandler` class +provides a :method:`Symfony\\Component\\ErrorHandler\\ErrorHandler::call` method that will +automatically throw an exception when such a failure occurs. This method will accept a ``callable`` +parameter and then the arguments needed to call it, returning back the result:: + + $content = ErrorHandler::call('file_get_contents', $filename); + +This way, you could use a ``\Closure`` function to wrap a portion of code and be sure that it +breaks even if the `@-silencing operator`_ is used:: + + $data = ErrorHandler::call(static function () use ($filename, $datetimeFormat) { + $data = json_decode(file_get_contents($filename), true); + $data['read_at'] = date($datetimeFormat); + file_put_contents($filename, json_encode($data)); + + return $data; + }); + .. _component-debug-class-loader: Debugging a Class Loader @@ -92,3 +147,6 @@ Using the ``DebugClassLoader`` is done by calling its static use Symfony\Component\ErrorHandler\DebugClassLoader; DebugClassLoader::enable(); + +.. _`@-silencing operator`: https://php.net/manual/en/function.json-decode.php +.. _`json_decode`: https://php.net/manual/en/language.operators.errorcontrol.php