Skip to content

Commit 06adb24

Browse files
committed
feature #10941 [Debug] cleanup interfaces before 2.5-final (nicolas-grekas)
This PR was merged into the 2.4-dev branch. Discussion ---------- [Debug] cleanup interfaces before 2.5-final | Q | A | ------------- | --- | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | none | License | MIT | Doc PR | none This PR is targeted at cleaning up interfaces before 2.5 final: - ExceptionHandlerInterface has never been released in a stable Symfony, lets drop it, not deprecate it, - generalize a little bit how fatal errors are handled and make them take the same path as uncaught exceptions, - enhance handling of out of memory situations. Commits ------- e3255bf [Debug] better ouf of memory error handling dfa8ff8 [Debug] cleanup interfaces before 2.5-final
2 parents b2855a5 + e3255bf commit 06adb24

File tree

10 files changed

+209
-187
lines changed

10 files changed

+209
-187
lines changed

src/Symfony/Bundle/FrameworkBundle/Resources/config/debug.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<parameter key="debug.stopwatch.class">Symfony\Component\Stopwatch\Stopwatch</parameter>
1010
<parameter key="debug.container.dump">%kernel.cache_dir%/%kernel.container_class%.xml</parameter>
1111
<parameter key="debug.controller_resolver.class">Symfony\Component\HttpKernel\Controller\TraceableControllerResolver</parameter>
12-
<parameter key="debug.fatal_error_exceptions_listener.class">Symfony\Component\HttpKernel\EventListener\FatalErrorExceptionsListener</parameter>
12+
<parameter key="debug.debug_handlers_listener.class">Symfony\Component\HttpKernel\EventListener\DebugHandlersListener</parameter>
1313
</parameters>
1414

1515
<services>
@@ -41,11 +41,11 @@
4141
<argument type="service" id="logger" on-invalid="null" />
4242
</service>
4343

44-
<service id="debug.fatal_error_exceptions_listener" class="%debug.fatal_error_exceptions_listener.class%">
44+
<service id="debug.debug_handlers_listener" class="%debug.debug_handlers_listener.class%">
4545
<tag name="kernel.event_subscriber" />
4646
<argument type="collection">
4747
<argument type="service" id="http_kernel" on-invalid="null" />
48-
<argument>handleFatalErrorException</argument>
48+
<argument>terminateWithException</argument>
4949
</argument>
5050
</service>
5151
</services>

src/Symfony/Component/Debug/CHANGELOG.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ CHANGELOG
44
2.5.0
55
-----
66

7-
* added ErrorHandler::setFatalErrorExceptionHandler()
7+
* added ExceptionHandler::setHandler()
88
* added UndefinedMethodFatalErrorHandler
9-
* deprecated ExceptionHandlerInterface
109
* deprecated DummyException
1110

1211
2.4.0

src/Symfony/Component/Debug/ErrorHandler.php

Lines changed: 17 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Psr\Log\LoggerInterface;
1616
use Symfony\Component\Debug\Exception\ContextErrorException;
1717
use Symfony\Component\Debug\Exception\FatalErrorException;
18+
use Symfony\Component\Debug\Exception\OutOfMemoryException;
1819
use Symfony\Component\Debug\FatalErrorHandler\UndefinedFunctionFatalErrorHandler;
1920
use Symfony\Component\Debug\FatalErrorHandler\UndefinedMethodFatalErrorHandler;
2021
use Symfony\Component\Debug\FatalErrorHandler\ClassNotFoundFatalErrorHandler;
@@ -53,8 +54,6 @@ class ErrorHandler
5354

5455
private $displayErrors;
5556

56-
private $caughtOutput = 0;
57-
5857
/**
5958
* @var LoggerInterface[] Loggers for channels
6059
*/
@@ -64,8 +63,6 @@ class ErrorHandler
6463

6564
private static $stackedErrorLevels = array();
6665

67-
private static $fatalHandler = false;
68-
6966
/**
7067
* Registers the error handler.
7168
*
@@ -119,16 +116,6 @@ public static function setLogger(LoggerInterface $logger, $channel = 'deprecatio
119116
self::$loggers[$channel] = $logger;
120117
}
121118

122-
/**
123-
* Sets a fatal error exception handler.
124-
*
125-
* @param callable $handler An handler that will be called on FatalErrorException
126-
*/
127-
public static function setFatalErrorExceptionHandler($handler)
128-
{
129-
self::$fatalHandler = $handler;
130-
}
131-
132119
/**
133120
* @throws ContextErrorException When error_reporting returns error
134121
*/
@@ -284,7 +271,7 @@ public function handleFatal()
284271
throw $exception;
285272
}
286273

287-
if (!$error || !$this->level || !in_array($error['type'], array(E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE))) {
274+
if (!$error || !$this->level || !($error['type'] & (E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_PARSE))) {
288275
return;
289276
}
290277

@@ -298,7 +285,7 @@ public function handleFatal()
298285
self::$loggers['emergency']->emergency($error['message'], $fatal);
299286
}
300287

301-
if ($this->displayErrors && ($exceptionHandler || self::$fatalHandler)) {
288+
if ($this->displayErrors && $exceptionHandler) {
302289
$this->handleFatalError($exceptionHandler, $error);
303290
}
304291
}
@@ -327,82 +314,25 @@ private function handleFatalError($exceptionHandler, array $error)
327314

328315
$level = isset($this->levels[$error['type']]) ? $this->levels[$error['type']] : $error['type'];
329316
$message = sprintf('%s: %s in %s line %d', $level, $error['message'], $error['file'], $error['line']);
330-
$exception = new FatalErrorException($message, 0, $error['type'], $error['file'], $error['line'], 3);
331-
332-
foreach ($this->getFatalErrorHandlers() as $handler) {
333-
if ($e = $handler->handleError($error, $exception)) {
334-
$exception = $e;
335-
break;
336-
}
337-
}
338-
339-
// To be as fail-safe as possible, the FatalErrorException is first handled
340-
// by the exception handler, then by the fatal error handler. The latter takes
341-
// precedence and any output from the former is cancelled, if and only if
342-
// nothing bad happens in this handling path.
343-
344-
$caughtOutput = 0;
345-
346-
if ($exceptionHandler) {
347-
$this->caughtOutput = false;
348-
ob_start(array($this, 'catchOutput'));
349-
try {
350-
call_user_func($exceptionHandler, $exception);
351-
} catch (\Exception $e) {
352-
// Ignore this exception, we have to deal with the fatal error
353-
}
354-
if (false === $this->caughtOutput) {
355-
ob_end_clean();
356-
}
357-
if (isset($this->caughtOutput[0])) {
358-
ob_start(array($this, 'cleanOutput'));
359-
echo $this->caughtOutput;
360-
$caughtOutput = ob_get_length();
361-
}
362-
$this->caughtOutput = 0;
363-
}
364-
365-
if (self::$fatalHandler) {
366-
try {
367-
call_user_func(self::$fatalHandler, $exception);
368-
369-
if ($caughtOutput) {
370-
$this->caughtOutput = $caughtOutput;
371-
}
372-
} catch (\Exception $e) {
373-
if (!$caughtOutput) {
374-
// Neither the exception nor the fatal handler succeeded.
375-
// Let PHP handle that now.
376-
throw $exception;
317+
if (0 === strpos($error['message'], 'Allowed memory') || 0 === strpos($error['message'], 'Out of memory')) {
318+
$exception = new OutOfMemoryException($message, 0, $error['type'], $error['file'], $error['line'], 3, false);
319+
} else {
320+
$exception = new FatalErrorException($message, 0, $error['type'], $error['file'], $error['line'], 3, true);
321+
322+
foreach ($this->getFatalErrorHandlers() as $handler) {
323+
if ($e = $handler->handleError($error, $exception)) {
324+
$exception = $e;
325+
break;
377326
}
378327
}
379328
}
380-
}
381-
382-
/**
383-
* @internal
384-
*/
385-
public function catchOutput($buffer)
386-
{
387-
$this->caughtOutput = $buffer;
388329

389-
return '';
390-
}
391-
392-
/**
393-
* @internal
394-
*/
395-
public function cleanOutput($buffer)
396-
{
397-
if ($this->caughtOutput) {
398-
// use substr_replace() instead of substr() for mbstring overloading resistance
399-
$cleanBuffer = substr_replace($buffer, '', 0, $this->caughtOutput);
400-
if (isset($cleanBuffer[0])) {
401-
$buffer = $cleanBuffer;
402-
}
330+
try {
331+
call_user_func($exceptionHandler, $exception);
332+
} catch (\Exception $e) {
333+
// The handler failed. Let PHP handle that now.
334+
throw $exception;
403335
}
404-
405-
return $buffer;
406336
}
407337
}
408338

src/Symfony/Component/Debug/Exception/FatalErrorException.php

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,36 +20,40 @@
2020
*/
2121
class FatalErrorException extends \ErrorException
2222
{
23-
public function __construct($message, $code, $severity, $filename, $lineno, $traceOffset = null)
23+
public function __construct($message, $code, $severity, $filename, $lineno, $traceOffset = null, $traceArgs = true)
2424
{
2525
parent::__construct($message, $code, $severity, $filename, $lineno);
2626

2727
if (null !== $traceOffset) {
2828
if (function_exists('xdebug_get_function_stack')) {
2929
$trace = xdebug_get_function_stack();
3030
if (0 < $traceOffset) {
31-
$trace = array_slice($trace, 0, -$traceOffset);
31+
array_splice($trace, -$traceOffset);
3232
}
33-
$trace = array_reverse($trace);
3433

35-
foreach ($trace as $i => $frame) {
34+
foreach ($trace as &$frame) {
3635
if (!isset($frame['type'])) {
3736
// XDebug pre 2.1.1 doesn't currently set the call type key http://bugs.xdebug.org/view.php?id=695
3837
if (isset($frame['class'])) {
39-
$trace[$i]['type'] = '::';
38+
$frame['type'] = '::';
4039
}
4140
} elseif ('dynamic' === $frame['type']) {
42-
$trace[$i]['type'] = '->';
41+
$frame['type'] = '->';
4342
} elseif ('static' === $frame['type']) {
44-
$trace[$i]['type'] = '::';
43+
$frame['type'] = '::';
4544
}
4645

4746
// XDebug also has a different name for the parameters array
48-
if (isset($frame['params']) && !isset($frame['args'])) {
49-
$trace[$i]['args'] = $frame['params'];
50-
unset($trace[$i]['params']);
47+
if (!$traceArgs) {
48+
unset($frame['params'], $frame['args']);
49+
} elseif (isset($frame['params']) && !isset($frame['args'])) {
50+
$frame['args'] = $frame['params'];
51+
unset($frame['params']);
5152
}
5253
}
54+
55+
unset($frame);
56+
$trace = array_reverse($trace);
5357
} else {
5458
$trace = array();
5559
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Debug\Exception;
13+
14+
/**
15+
* Out of memory exception.
16+
*
17+
* @author Nicolas Grekas <p@tchwork.com>
18+
*/
19+
class OutOfMemoryException extends FatalErrorException
20+
{
21+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy