Skip to content

Commit dfa8ff8

Browse files
[Debug] cleanup interfaces before 2.5-final
1 parent b2855a5 commit dfa8ff8

File tree

8 files changed

+156
-173
lines changed

8 files changed

+156
-173
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: 7 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,6 @@ class ErrorHandler
5353

5454
private $displayErrors;
5555

56-
private $caughtOutput = 0;
57-
5856
/**
5957
* @var LoggerInterface[] Loggers for channels
6058
*/
@@ -64,8 +62,6 @@ class ErrorHandler
6462

6563
private static $stackedErrorLevels = array();
6664

67-
private static $fatalHandler = false;
68-
6965
/**
7066
* Registers the error handler.
7167
*
@@ -119,16 +115,6 @@ public static function setLogger(LoggerInterface $logger, $channel = 'deprecatio
119115
self::$loggers[$channel] = $logger;
120116
}
121117

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-
132118
/**
133119
* @throws ContextErrorException When error_reporting returns error
134120
*/
@@ -284,7 +270,7 @@ public function handleFatal()
284270
throw $exception;
285271
}
286272

287-
if (!$error || !$this->level || !in_array($error['type'], array(E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE))) {
273+
if (!$error || !$this->level || !($error['type'] & (E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_PARSE))) {
288274
return;
289275
}
290276

@@ -298,7 +284,7 @@ public function handleFatal()
298284
self::$loggers['emergency']->emergency($error['message'], $fatal);
299285
}
300286

301-
if ($this->displayErrors && ($exceptionHandler || self::$fatalHandler)) {
287+
if ($this->displayErrors && $exceptionHandler) {
302288
$this->handleFatalError($exceptionHandler, $error);
303289
}
304290
}
@@ -336,73 +322,12 @@ private function handleFatalError($exceptionHandler, array $error)
336322
}
337323
}
338324

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;
377-
}
378-
}
379-
}
380-
}
381-
382-
/**
383-
* @internal
384-
*/
385-
public function catchOutput($buffer)
386-
{
387-
$this->caughtOutput = $buffer;
388-
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-
}
325+
try {
326+
call_user_func($exceptionHandler, $exception);
327+
} catch (\Exception $e) {
328+
// The handler failed. Let PHP handle that now.
329+
throw $exception;
403330
}
404-
405-
return $buffer;
406331
}
407332
}
408333

src/Symfony/Component/Debug/ExceptionHandler.php

Lines changed: 88 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,12 @@
2929
*
3030
* @author Fabien Potencier <[email protected]>
3131
*/
32-
class ExceptionHandler implements ExceptionHandlerInterface
32+
class ExceptionHandler
3333
{
3434
private $debug;
3535
private $charset;
36+
private $handler;
37+
private $caughtOutput = 0;
3638

3739
public function __construct($debug = true, $charset = 'UTF-8')
3840
{
@@ -56,6 +58,22 @@ public static function register($debug = true)
5658
return $handler;
5759
}
5860

61+
/**
62+
* Sets a user exception handler.
63+
*
64+
* @param callable $handler An handler that will be called on Exception
65+
*/
66+
public function setHandler($handler)
67+
{
68+
if (isset($handler) && !is_callable($handler)) {
69+
throw new \LogicException('The exception handler must be a valid PHP callable.');
70+
}
71+
$old = $this->handler;
72+
$this->handler = $handler;
73+
74+
return $old;
75+
}
76+
5977
/**
6078
* {@inheritdoc}
6179
*
@@ -70,12 +88,49 @@ public static function register($debug = true)
7088
*/
7189
public function handle(\Exception $exception)
7290
{
73-
if (class_exists('Symfony\Component\HttpFoundation\Response')) {
74-
$response = $this->createResponse($exception);
75-
$response->sendHeaders();
76-
$response->sendContent();
77-
} else {
78-
$this->sendPhpResponse($exception);
91+
// To be as fail-safe as possible, the exception is first handled
92+
// by our simple exception handler, then by the user exception handler.
93+
// The latter takes precedence and any output from the former is cancelled,
94+
// if and only if nothing bad happens in this handling path.
95+
96+
$caughtOutput = 0;
97+
98+
$this->caughtOutput = false;
99+
ob_start(array($this, 'catchOutput'));
100+
try {
101+
if (class_exists('Symfony\Component\HttpFoundation\Response')) {
102+
$response = $this->createResponse($exception);
103+
$response->sendHeaders();
104+
$response->sendContent();
105+
} else {
106+
$this->sendPhpResponse($exception);
107+
}
108+
} catch (\Exception $e) {
109+
// Ignore this $e exception, we have to deal with $exception
110+
}
111+
if (false === $this->caughtOutput) {
112+
ob_end_clean();
113+
}
114+
if (isset($this->caughtOutput[0])) {
115+
ob_start(array($this, 'cleanOutput'));
116+
echo $this->caughtOutput;
117+
$caughtOutput = ob_get_length();
118+
}
119+
$this->caughtOutput = 0;
120+
121+
if (!empty($this->handler)) {
122+
try {
123+
call_user_func($this->handler, $exception);
124+
125+
if ($caughtOutput) {
126+
$this->caughtOutput = $caughtOutput;
127+
}
128+
} catch (\Exception $e) {
129+
if (!$caughtOutput) {
130+
// All handlers failed. Let PHP handle that now.
131+
throw $exception;
132+
}
133+
}
79134
}
80135
}
81136

@@ -317,4 +372,30 @@ private function formatArgs(array $args)
317372

318373
return implode(', ', $result);
319374
}
375+
376+
/**
377+
* @internal
378+
*/
379+
public function catchOutput($buffer)
380+
{
381+
$this->caughtOutput = $buffer;
382+
383+
return '';
384+
}
385+
386+
/**
387+
* @internal
388+
*/
389+
public function cleanOutput($buffer)
390+
{
391+
if ($this->caughtOutput) {
392+
// use substr_replace() instead of substr() for mbstring overloading resistance
393+
$cleanBuffer = substr_replace($buffer, '', 0, $this->caughtOutput);
394+
if (isset($cleanBuffer[0])) {
395+
$buffer = $cleanBuffer;
396+
}
397+
}
398+
399+
return $buffer;
400+
}
320401
}

src/Symfony/Component/Debug/ExceptionHandlerInterface.php

Lines changed: 0 additions & 29 deletions
This file was deleted.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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\HttpKernel\EventListener;
13+
14+
use Symfony\Component\Debug\ExceptionHandler;
15+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
16+
use Symfony\Component\HttpKernel\KernelEvents;
17+
18+
/**
19+
* Configures the ExceptionHandler.
20+
*
21+
* @author Nicolas Grekas <[email protected]>
22+
*/
23+
class DebugHandlersListener implements EventSubscriberInterface
24+
{
25+
private $exceptionHandler;
26+
27+
public function __construct($exceptionHandler)
28+
{
29+
if (is_callable($exceptionHandler)) {
30+
$this->exceptionHandler = $exceptionHandler;
31+
}
32+
}
33+
34+
public function configure()
35+
{
36+
if ($this->exceptionHandler) {
37+
$mainHandler = set_exception_handler('var_dump');
38+
restore_exception_handler();
39+
if ($mainHandler instanceof ExceptionHandler) {
40+
$mainHandler->setHandler($this->exceptionHandler);
41+
}
42+
$this->exceptionHandler = null;
43+
}
44+
}
45+
46+
public static function getSubscribedEvents()
47+
{
48+
return array(KernelEvents::REQUEST => array('configure', 2048));
49+
}
50+
}

0 commit comments

Comments
 (0)