[!!!][BUGFIX] Accept \Throwable in ExceptionHandlerInterface 47/45247/6
authorAlexander Opitz <opitz.alexander@googlemail.com>
Mon, 14 Dec 2015 16:30:46 +0000 (17:30 +0100)
committerBenni Mack <benni@typo3.org>
Fri, 18 Dec 2015 14:20:33 +0000 (15:20 +0100)
Since PHP 7.0 \Exceptions are a subclass of \Throwable, and some PHP
Errors are thrown as \Throwables. So we need to support \Throwables
inside Exception handling.
http://php.net/manual/en/language.errors.php7.php

Resolves: #72117
Releases: master
Change-Id: I4302ab0f91386c4764a1b0e0305cd947987d60eb
Reviewed-on: https://review.typo3.org/45247
Reviewed-by: Frank N├Ągler <frank.naegler@typo3.org>
Reviewed-by: Benni Mack <benni@typo3.org>
Reviewed-by: Oliver Hader <oliver.hader@typo3.org>
Tested-by: Oliver Hader <oliver.hader@typo3.org>
Tested-by: Benni Mack <benni@typo3.org>
typo3/sysext/backend/Classes/Console/CliRequestHandler.php
typo3/sysext/core/Classes/Error/AbstractExceptionHandler.php
typo3/sysext/core/Classes/Error/DebugExceptionHandler.php
typo3/sysext/core/Classes/Error/ExceptionHandlerInterface.php
typo3/sysext/core/Classes/Error/ProductionExceptionHandler.php
typo3/sysext/core/Documentation/Changelog/master/Breaking-72117-APIChangeInExceptionHandlerInterface.rst [new file with mode: 0644]

index ff8bc36..08fbe03 100755 (executable)
@@ -88,6 +88,9 @@ class CliRequestHandler implements RequestHandlerInterface
         } catch (\Exception $e) {
             $output->writeln('<error>Oops, an error occurred: ' . $e->getMessage() . '</error>');
             $exitCode = $e->getCode();
+        } catch (\Throwable $e) {
+            $output->writeln('<error>Oops, an error occurred: ' . $e->getMessage() . '</error>');
+            $exitCode = $e->getCode();
         }
 
         exit($exitCode);
index d045389..04c617e 100644 (file)
@@ -30,29 +30,36 @@ abstract class AbstractExceptionHandler implements ExceptionHandlerInterface, \T
     /**
      * Displays the given exception
      *
-     * @param \Exception $exception The exception object
-     * @return void
+     * @param \Exception|\Throwable $exception The exception(PHP 5.x) or throwable(PHP >= 7.0) object.
+     * @TODO #72293 This will change to \Throwable only if we are >= PHP7.0 only
+     *
+     * @throws \Exception
      */
-    public function handleException(\Exception $exception)
+    public function handleException($exception)
     {
-        switch (PHP_SAPI) {
-            case 'cli':
-                $this->echoExceptionCLI($exception);
-                break;
-            default:
-                $this->echoExceptionWeb($exception);
+        if ($exception instanceof \Throwable || $exception instanceof \Exception) {
+            switch (PHP_SAPI) {
+                case 'cli':
+                    $this->echoExceptionCLI($exception);
+                    break;
+                default:
+                    $this->echoExceptionWeb($exception);
+            }
+        } else {
+            throw new \Exception('handleException was called the wrong way.');
         }
     }
 
     /**
      * Writes exception to different logs
      *
-     * @param \Exception $exception The exception
+     * @param \Exception|\Throwable $exception The exception(PHP 5.x) or throwable(PHP >= 7.0) object.
      * @param string $context The context where the exception was thrown, WEB or CLI
      * @return void
      * @see \TYPO3\CMS\Core\Utility\GeneralUtility::sysLog(), \TYPO3\CMS\Core\Utility\GeneralUtility::devLog()
+     * @TODO #72293 This will change to \Throwable only if we are >= PHP7.0 only
      */
-    protected function writeLogEntries(\Exception $exception, $context)
+    protected function writeLogEntries($exception, $context)
     {
         // Do not write any logs for this message to avoid filling up tables or files with illegal requests
         if ($exception->getCode() === 1396795884) {
@@ -127,10 +134,11 @@ abstract class AbstractExceptionHandler implements ExceptionHandlerInterface, \T
      * Sends the HTTP Status 500 code, if $exception is *not* a
      * TYPO3\CMS\Core\Error\Http\StatusException and headers are not sent, yet.
      *
-     * @param \Exception $exception
+     * @param \Exception|\Throwable $exception The exception(PHP 5.x) or throwable(PHP >= 7.0) object.
      * @return void
+     * @TODO #72293 This will change to \Throwable only if we are >= PHP7.0 only
      */
-    protected function sendStatusHeaders(\Exception $exception)
+    protected function sendStatusHeaders($exception)
     {
         if (method_exists($exception, 'getStatusHeaders')) {
             $headers = $exception->getStatusHeaders();
index bea9771..b7acf72 100644 (file)
@@ -34,10 +34,11 @@ class DebugExceptionHandler extends AbstractExceptionHandler
     /**
      * Formats and echoes the exception as XHTML.
      *
-     * @param \Exception $exception The exception object
+     * @param \Exception|\Throwable $exception The exception object
      * @return void
+     * @TODO #72293 This will change to \Throwable only if we are >= PHP7.0 only
      */
-    public function echoExceptionWeb(\Exception $exception)
+    public function echoExceptionWeb($exception)
     {
         $this->sendStatusHeaders($exception);
         $filePathAndName = $exception->getFile();
@@ -112,10 +113,11 @@ class DebugExceptionHandler extends AbstractExceptionHandler
     /**
      * Formats and echoes the exception for the command line
      *
-     * @param \Exception $exception The exception object
+     * @param \Exception|\Throwable $exception The exception object
      * @return void
+     * @TODO #72293 This will change to \Throwable only if we are >= PHP7.0 only
      */
-    public function echoExceptionCLI(\Exception $exception)
+    public function echoExceptionCLI($exception)
     {
         $filePathAndName = $exception->getFile();
         $exceptionCodeNumber = $exception->getCode() > 0 ? '#' . $exception->getCode() . ': ' : '';
index 87928fb..97f1081 100644 (file)
@@ -29,24 +29,27 @@ interface ExceptionHandlerInterface
     /**
      * Handles the given exception
      *
-     * @param \Exception $exception: The exception object
+     * @param \Exception|\Throwable $exception The exception(PHP 5.x) or throwable(PHP >= 7.0) object.
      * @return void
+     * @TODO #72293 This will change to \Throwable only if we are >= PHP7.0 only
      */
-    public function handleException(\Exception $exception);
+    public function handleException($exception);
 
     /**
      * Formats and echoes the exception as XHTML.
      *
-     * @param \Exception $exception The exception object
+     * @param \Exception|\Throwable $exception The exception(PHP 5.x) or throwable(PHP >= 7.0) object.
      * @return void
+     * @TODO #72293 This will change to \Throwable only if we are >= PHP7.0 only
      */
-    public function echoExceptionWeb(\Exception $exception);
+    public function echoExceptionWeb($exception);
 
     /**
      * Formats and echoes the exception for the command line
      *
-     * @param \Exception $exception The exception object
+     * @param \Exception|\Throwable $exception The exception(PHP 5.x) or throwable(PHP >= 7.0) object.
      * @return void
+     * @TODO #72293 This will change to \Throwable only if we are >= PHP7.0 only
      */
-    public function echoExceptionCLI(\Exception $exception);
+    public function echoExceptionCLI($exception);
 }
index de8023e..926bd61 100644 (file)
@@ -46,10 +46,11 @@ class ProductionExceptionHandler extends AbstractExceptionHandler
     /**
      * Echoes an exception for the web.
      *
-     * @param \Exception $exception The exception
+     * @param \Exception|\Throwable $exception The exception
      * @return void
+     * @TODO #72293 This will change to \Throwable only if we are >= PHP7.0 only
      */
-    public function echoExceptionWeb(\Exception $exception)
+    public function echoExceptionWeb($exception)
     {
         $this->sendStatusHeaders($exception);
         $this->writeLogEntries($exception, self::CONTEXT_WEB);
@@ -64,10 +65,11 @@ class ProductionExceptionHandler extends AbstractExceptionHandler
     /**
      * Echoes an exception for the command line.
      *
-     * @param \Exception $exception The exception
+     * @param \Exception|\Throwable $exception The exception
      * @return void
+     * @TODO #72293 This will change to \Throwable only if we are >= PHP7.0 only
      */
-    public function echoExceptionCLI(\Exception $exception)
+    public function echoExceptionCLI($exception)
     {
         $filePathAndName = $exception->getFile();
         $exceptionCodeNumber = $exception->getCode() > 0 ? '#' . $exception->getCode() . ': ' : '';
@@ -84,10 +86,11 @@ Uncaught TYPO3 Exception ' . $exceptionCodeNumber . $exception->getMessage() . L
     /**
      * Determines, whether Exception details should be outputted
      *
-     * @param \Exception $exception The exception
+     * @param \Exception|\Throwable $exception The exception
      * @return bool
+     * @TODO #72293 This will change to \Throwable only if we are >= PHP7.0 only
      */
-    protected function discloseExceptionInformation(\Exception $exception)
+    protected function discloseExceptionInformation($exception)
     {
         // Allow message to be shown in production mode if the exception is about
         // trusted host configuration.  By doing so we do not disclose
@@ -110,10 +113,11 @@ Uncaught TYPO3 Exception ' . $exceptionCodeNumber . $exception->getMessage() . L
     /**
      * Returns the title for the error message
      *
-     * @param \Exception $exception Exception causing the error
+     * @param \Exception|\Throwable $exception Exception causing the error
      * @return string
+     * @TODO #72293 This will change to \Throwable only if we are >= PHP7.0 only
      */
-    protected function getTitle(\Exception $exception)
+    protected function getTitle($exception)
     {
         if ($this->discloseExceptionInformation($exception) && method_exists($exception, 'getTitle') && $exception->getTitle() !== '') {
             return htmlspecialchars($exception->getTitle());
@@ -125,10 +129,11 @@ Uncaught TYPO3 Exception ' . $exceptionCodeNumber . $exception->getMessage() . L
     /**
      * Returns the message for the error message
      *
-     * @param \Exception $exception Exception causing the error
+     * @param \Exception|\Throwable $exception Exception causing the error
      * @return string
+     * @TODO #72293 This will change to \Throwable only if we are >= PHP7.0 only
      */
-    protected function getMessage(\Exception $exception)
+    protected function getMessage($exception)
     {
         if ($this->discloseExceptionInformation($exception)) {
             // Exception has an error code given
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Breaking-72117-APIChangeInExceptionHandlerInterface.rst b/typo3/sysext/core/Documentation/Changelog/master/Breaking-72117-APIChangeInExceptionHandlerInterface.rst
new file mode 100644 (file)
index 0000000..f42783a
--- /dev/null
@@ -0,0 +1,27 @@
+==========================================================
+Breaking: #72117 - API change in ExceptionHandlerInterface
+==========================================================
+
+Description
+===========
+
+The class \Throwable was added in PHP7 as new parent of \Exceptions. This leads to the issue that ExceptionHandlers need to change the API of their exception handling method. To support PHP 5.5, 5.6 and 7.0 we need to remove the type hint. It will later be set to \Throwable if we only support PHP 7.0 and newer.
+See http://php.net/manual/en/migration70.incompatible.php
+
+
+Impact
+======
+
+A fatal error will be thrown if you use own ExceptionHandlers implementing TYPO3\CMS\Core\Error\ExceptionHandlerInterface "Fatal error: Declaration of ... must be compatible with ..."
+
+
+Affected Installations
+======================
+
+Installations which use an own ExceptionHandler implementing TYPO3s ExceptionHandlerInterface.
+
+
+Migration
+=========
+
+Remove the type hinting in your implementation of ExceptionHandlerInterface. If you switch to PHP 7 you may also get instances from \Throwable, so check the API/type hinting of the function were you process the exception.