diff --git a/src/error/PhutilProxyException.php b/src/error/PhutilProxyException.php index 8326959..4f477ae 100644 --- a/src/error/PhutilProxyException.php +++ b/src/error/PhutilProxyException.php @@ -1,32 +1,37 @@ previousException = $previous; - if (version_compare(PHP_VERSION, '5.3.0', '>=')) { + // This may be an "Exception" or a "Throwable". The "__construct()" method + // for the Exception is documented as taking an Exception, not a Throwable. + // Although passing a Throwable appears to work in PHP 7.3, don't risk it. + $is_exception = ($previous instanceof Exception); + + if (version_compare(PHP_VERSION, '5.3.0', '>=') && $is_exception) { parent::__construct($message, $code, $previous); } else { parent::__construct($message, $code); } } public function getPreviousException() { // NOTE: This can not be named "getPrevious()" because that method is final // after PHP 5.3. Similarly, the property can not be named "previous" // because HPHP declares a property with the same name and "protected" // visibility. return $this->previousException; } } diff --git a/src/error/phlog.php b/src/error/phlog.php index a36d0aa..105e074 100644 --- a/src/error/phlog.php +++ b/src/error/phlog.php @@ -1,68 +1,68 @@ $trace[0]['file'], 'line' => $trace[0]['line'], 'trace' => $trace, ); foreach (func_get_args() as $event) { $data = $metadata; - if ($event instanceof Exception) { + if (($event instanceof Exception) || ($event instanceof Throwable)) { $type = PhutilErrorHandler::EXCEPTION; // If this is an exception, proxy it and generate a composite trace which // shows both where the phlog() was called and where the exception was // originally thrown from. $proxy = new PhutilProxyException('', $event); $trace = PhutilErrorHandler::getExceptionTrace($proxy); $data['trace'] = $trace; } else { $type = PhutilErrorHandler::PHLOG; } PhutilErrorHandler::dispatchErrorMessage($type, $event, $data); } return $value; } /** * Example @{class:PhutilErrorHandler} error listener callback. When you call * `PhutilErrorHandler::setErrorListener()`, you must pass a callback function * with the same signature as this one. * * NOTE: @{class:PhutilErrorHandler} handles writing messages to the error * log, so you only need to provide a listener if you have some other console * (like Phabricator's DarkConsole) which you //also// want to send errors to. * * NOTE: You will receive errors which were silenced with the `@` operator. If * you don't want to display these, test for `@` being in effect by checking if * `error_reporting() === 0` before displaying the error. * * @param const A PhutilErrorHandler constant, like PhutilErrorHandler::ERROR, * which indicates the event type (e.g. error, exception, * user message). * @param wild The event value, like the Exception object for an exception * event, an error string for an error event, or some user object * for user messages. * @param dict A dictionary of metadata about the event. The keys 'file', * 'line' and 'trace' are always available. Other keys may be * present, depending on the event type. * @return void */ function phutil_error_listener_example($event, $value, array $metadata) { throw new Exception(pht('This is just an example function!')); }