merged branch ShiraNai7/master (PR #8688)
This PR was submitted for the master branch but it was merged into the 2.3 branch instead (closes #8688). Discussion ---------- [Debug] Make sure ContextErrorException is loaded during compile time errors | Q | A | ------------- | --- | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | no | Fixed tickets | n/a | License | MIT | Doc PR | n/a ### Description When the `ErrorHandler->handle()` attempts to throw a `ContextErrorException` the script might die with a Fatal Error because the class is not found. FatalErrorException: Error: Class 'Symfony\Component\Debug\Exception\ContextErrorException' not found in ... That effectively hides the original error and causes confusion. ### Cause The cause is a bug/limitation of PHP that makes class autoloading completely inactive during "compiling". Relevant PHP source code in `zend_execute_API.c`: /* The compiler is not-reentrant. Make sure we __autoload() only during run-time * (doesn't impact functionality of __autoload() */ if (!use_autoload || zend_is_compiling(TSRMLS_C)) { #### More information about the PHP bug/limitation: - https://bugs.php.net/bug.php?id=65322 - many duplicates/relevant: https://www.google.com/search?btnG=1&pws=0&q=site%3Abugs.php.net+autoload+error+handling ### The fix The most simple way to fix this is to manually ensure that `ContextErrorException` is loaded and if not, load it. This is what I did. Another way is to detect if autoloading is available (possible by prepending a temporary autoloader) and act accordingly (how?). ### The test I also added a test case that would fail with a fatal error if the error handler does not successfully throw an exception in case of a compile time error. But I'm not sure if this is the best way or if there should be a test case at all. ### Commits ------- b0082ab [Debug] Make sure ContextErrorException is loaded during compile time errors
This commit is contained in:
commit
0d16f5dd45
@ -120,6 +120,11 @@ class ErrorHandler
|
||||
}
|
||||
|
||||
if ($this->displayErrors && error_reporting() & $level && $this->level & $level) {
|
||||
// make sure the ContextErrorException class is loaded (https://bugs.php.net/bug.php?id=65322)
|
||||
if (!class_exists('Symfony\Component\Debug\Exception\ContextErrorException')) {
|
||||
require __DIR__.'/Exception/ContextErrorException.php';
|
||||
}
|
||||
|
||||
throw new ContextErrorException(sprintf('%s: %s in %s line %d', isset($this->levels[$level]) ? $this->levels[$level] : $level, $message, $file, $line), 0, $level, $file, $line, $context);
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,31 @@ use Symfony\Component\Debug\ErrorHandler;
|
||||
*/
|
||||
class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testCompileTimeError()
|
||||
{
|
||||
// the ContextErrorException must not be loaded for this test to work
|
||||
if (class_exists('Symfony\Component\Debug\Exception\ContextErrorException', false)) {
|
||||
$this->markTestSkipped('The ContextErrorException class is already loaded.');
|
||||
}
|
||||
|
||||
$handler = ErrorHandler::register(E_ALL | E_STRICT);
|
||||
$displayErrors = ini_get('display_errors');
|
||||
ini_set('display_errors', '1');
|
||||
|
||||
try {
|
||||
// trigger compile time error
|
||||
eval(<<<'PHP'
|
||||
class _BaseCompileTimeError { function foo() {} }
|
||||
class _CompileTimeError extends _BaseCompileTimeError { function foo($invalid) {} }
|
||||
PHP
|
||||
);
|
||||
} catch(\Exception $e) {
|
||||
// if an exception is thrown, the test passed
|
||||
}
|
||||
|
||||
ini_set('display_errors', $displayErrors);
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
public function testConstruct()
|
||||
{
|
||||
|
Reference in New Issue
Block a user