mirror of
https://github.com/symfony/debug.git
synced 2026-03-25 17:52:07 +01:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ce874f443 | ||
|
|
f34d2bf035 | ||
|
|
518c6a00d0 | ||
|
|
2560754c36 | ||
|
|
44897cd605 | ||
|
|
7e9cd457b4 | ||
|
|
ce9f3b5e8e | ||
|
|
ed3231ef38 | ||
|
|
a99278d50a | ||
|
|
70dd18e93b | ||
|
|
9a81b6360b | ||
|
|
cbe127b719 | ||
|
|
9d32af2d83 |
@@ -223,14 +223,14 @@ class ErrorHandler
|
||||
if (!\is_array($log)) {
|
||||
$log = [$log];
|
||||
} elseif (!\array_key_exists(0, $log)) {
|
||||
throw new \InvalidArgumentException('No logger provided');
|
||||
throw new \InvalidArgumentException('No logger provided.');
|
||||
}
|
||||
if (null === $log[0]) {
|
||||
$this->loggedErrors &= ~$type;
|
||||
} elseif ($log[0] instanceof LoggerInterface) {
|
||||
$this->loggedErrors |= $type;
|
||||
} else {
|
||||
throw new \InvalidArgumentException('Invalid logger provided');
|
||||
throw new \InvalidArgumentException('Invalid logger provided.');
|
||||
}
|
||||
$this->loggers[$type] = $log + $prev[$type];
|
||||
|
||||
@@ -401,7 +401,7 @@ class ErrorHandler
|
||||
$scope = $this->scopedErrors & $type;
|
||||
|
||||
if (4 < $numArgs = \func_num_args()) {
|
||||
$context = $scope ? (func_get_arg(4) ?: []) : [];
|
||||
$context = func_get_arg(4) ?: [];
|
||||
$backtrace = 5 < $numArgs ? func_get_arg(5) : null; // defined on HHVM
|
||||
} else {
|
||||
$context = [];
|
||||
@@ -521,7 +521,7 @@ class ErrorHandler
|
||||
$errorAsException ? ['exception' => $errorAsException] : [],
|
||||
];
|
||||
} else {
|
||||
if (!\defined('HHVM_VERSION')) {
|
||||
if (\PHP_VERSION_ID < (\PHP_VERSION_ID < 70400 ? 70316 : 70404) && !\defined('HHVM_VERSION')) {
|
||||
$currentErrorHandler = set_error_handler('var_dump');
|
||||
restore_error_handler();
|
||||
}
|
||||
@@ -533,7 +533,7 @@ class ErrorHandler
|
||||
} finally {
|
||||
$this->isRecursive = false;
|
||||
|
||||
if (!\defined('HHVM_VERSION')) {
|
||||
if (\PHP_VERSION_ID < (\PHP_VERSION_ID < 70400 ? 70316 : 70404) && !\defined('HHVM_VERSION')) {
|
||||
set_error_handler($currentErrorHandler);
|
||||
}
|
||||
}
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2004-2019 Fabien Potencier
|
||||
Copyright (c) 2004-2020 Fabien Potencier
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
14
README.md
14
README.md
@@ -3,10 +3,22 @@ Debug Component
|
||||
|
||||
The Debug component provides tools to ease debugging PHP code.
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
|
||||
```
|
||||
$ composer install symfony/debug
|
||||
```
|
||||
|
||||
```php
|
||||
use Symfony\Component\Debug\Debug;
|
||||
|
||||
Debug::enable();
|
||||
```
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
* [Documentation](https://symfony.com/doc/current/components/debug/index.html)
|
||||
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
|
||||
* [Report issues](https://github.com/symfony/symfony/issues) and
|
||||
[send Pull Requests](https://github.com/symfony/symfony/pulls)
|
||||
|
||||
@@ -64,14 +64,14 @@ class DebugClassLoaderTest extends TestCase
|
||||
$this->expectException('Exception');
|
||||
$this->expectExceptionMessage('boo');
|
||||
try {
|
||||
class_exists(__NAMESPACE__.'\Fixtures\Throwing');
|
||||
class_exists(Fixtures\Throwing::class);
|
||||
$this->fail('Exception expected');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertSame('boo', $e->getMessage());
|
||||
}
|
||||
|
||||
// the second call also should throw
|
||||
class_exists(__NAMESPACE__.'\Fixtures\Throwing');
|
||||
class_exists(Fixtures\Throwing::class);
|
||||
}
|
||||
|
||||
public function testUnsilencing()
|
||||
@@ -90,13 +90,16 @@ class DebugClassLoaderTest extends TestCase
|
||||
|
||||
// See below: this will fail with parse error
|
||||
// but this should not be @-silenced.
|
||||
@class_exists(__NAMESPACE__.'\TestingUnsilencing', true);
|
||||
@class_exists(TestingUnsilencing::class, true);
|
||||
|
||||
$output = ob_get_clean();
|
||||
|
||||
$this->assertStringMatchesFormat('%aParse error%a', $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* @requires PHP < 8.0
|
||||
*/
|
||||
public function testStacking()
|
||||
{
|
||||
// the ContextErrorException must not be loaded to test the workaround
|
||||
@@ -141,7 +144,7 @@ class DebugClassLoaderTest extends TestCase
|
||||
{
|
||||
$this->expectException('RuntimeException');
|
||||
$this->expectExceptionMessage('Case mismatch between loaded and declared class names');
|
||||
class_exists(__NAMESPACE__.'\TestingCaseMismatch', true);
|
||||
class_exists(TestingCaseMismatch::class, true);
|
||||
}
|
||||
|
||||
public function testFileCaseMismatch()
|
||||
@@ -152,7 +155,7 @@ class DebugClassLoaderTest extends TestCase
|
||||
$this->markTestSkipped('Can only be run on case insensitive filesystems');
|
||||
}
|
||||
|
||||
class_exists(__NAMESPACE__.'\Fixtures\CaseMismatch', true);
|
||||
class_exists(Fixtures\CaseMismatch::class, true);
|
||||
}
|
||||
|
||||
public function testPsr4CaseMismatch()
|
||||
@@ -174,7 +177,7 @@ class DebugClassLoaderTest extends TestCase
|
||||
|
||||
public function testClassAlias()
|
||||
{
|
||||
$this->assertTrue(class_exists(__NAMESPACE__.'\Fixtures\ClassAlias', true));
|
||||
$this->assertTrue(class_exists(Fixtures\ClassAlias::class, true));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -216,7 +219,7 @@ class DebugClassLoaderTest extends TestCase
|
||||
$e = error_reporting(0);
|
||||
trigger_error('', E_USER_NOTICE);
|
||||
|
||||
class_exists('Test\\'.__NAMESPACE__.'\\NonDeprecatedInterfaceClass', true);
|
||||
class_exists('Test\\'.NonDeprecatedInterfaceClass::class, true);
|
||||
|
||||
error_reporting($e);
|
||||
restore_error_handler();
|
||||
@@ -264,7 +267,7 @@ class DebugClassLoaderTest extends TestCase
|
||||
$e = error_reporting(0);
|
||||
trigger_error('', E_USER_NOTICE);
|
||||
|
||||
class_exists('Test\\'.__NAMESPACE__.'\\Float', true);
|
||||
class_exists('Test\\'.Float::class, true);
|
||||
|
||||
error_reporting($e);
|
||||
restore_error_handler();
|
||||
@@ -289,7 +292,7 @@ class DebugClassLoaderTest extends TestCase
|
||||
require __DIR__.'/Fixtures/FinalClasses.php';
|
||||
|
||||
$i = 1;
|
||||
while (class_exists($finalClass = __NAMESPACE__.'\\Fixtures\\FinalClass'.$i++, false)) {
|
||||
while (class_exists($finalClass = Fixtures\FinalClass::class.$i++, false)) {
|
||||
spl_autoload_call($finalClass);
|
||||
class_exists('Test\\'.__NAMESPACE__.'\\Extends'.substr($finalClass, strrpos($finalClass, '\\') + 1), true);
|
||||
}
|
||||
@@ -315,7 +318,7 @@ class DebugClassLoaderTest extends TestCase
|
||||
set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; });
|
||||
$e = error_reporting(E_USER_DEPRECATED);
|
||||
|
||||
class_exists(__NAMESPACE__.'\\Fixtures\\ExtendedFinalMethod', true);
|
||||
class_exists(Fixtures\ExtendedFinalMethod::class, true);
|
||||
|
||||
error_reporting($e);
|
||||
restore_error_handler();
|
||||
@@ -334,7 +337,7 @@ class DebugClassLoaderTest extends TestCase
|
||||
$e = error_reporting(0);
|
||||
trigger_error('', E_USER_NOTICE);
|
||||
|
||||
class_exists('Test\\'.__NAMESPACE__.'\\ExtendsAnnotatedClass', true);
|
||||
class_exists('Test\\'.ExtendsAnnotatedClass::class, true);
|
||||
|
||||
error_reporting($e);
|
||||
restore_error_handler();
|
||||
@@ -351,7 +354,7 @@ class DebugClassLoaderTest extends TestCase
|
||||
set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; });
|
||||
$e = error_reporting(E_USER_DEPRECATED);
|
||||
|
||||
class_exists('Test\\'.__NAMESPACE__.'\\ExtendsInternals', true);
|
||||
class_exists('Test\\'.ExtendsInternals::class, true);
|
||||
|
||||
error_reporting($e);
|
||||
restore_error_handler();
|
||||
@@ -370,7 +373,7 @@ class DebugClassLoaderTest extends TestCase
|
||||
set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; });
|
||||
$e = error_reporting(E_USER_DEPRECATED);
|
||||
|
||||
class_exists('Test\\'.__NAMESPACE__.'\\UseTraitWithInternalMethod', true);
|
||||
class_exists('Test\\'.UseTraitWithInternalMethod::class, true);
|
||||
|
||||
error_reporting($e);
|
||||
restore_error_handler();
|
||||
@@ -380,7 +383,7 @@ class DebugClassLoaderTest extends TestCase
|
||||
|
||||
public function testEvaluatedCode()
|
||||
{
|
||||
$this->assertTrue(class_exists(__NAMESPACE__.'\Fixtures\DefinitionInEvaluatedCode', true));
|
||||
$this->assertTrue(class_exists(Fixtures\DefinitionInEvaluatedCode::class, true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -399,11 +402,11 @@ class ClassLoader
|
||||
{
|
||||
$fixtureDir = __DIR__.\DIRECTORY_SEPARATOR.'Fixtures'.\DIRECTORY_SEPARATOR;
|
||||
|
||||
if (__NAMESPACE__.'\TestingUnsilencing' === $class) {
|
||||
if (TestingUnsilencing::class === $class) {
|
||||
eval('-- parse error --');
|
||||
} elseif (__NAMESPACE__.'\TestingStacking' === $class) {
|
||||
} elseif (TestingStacking::class === $class) {
|
||||
eval('namespace '.__NAMESPACE__.'; class TestingStacking { function foo() {} }');
|
||||
} elseif (__NAMESPACE__.'\TestingCaseMismatch' === $class) {
|
||||
} elseif (TestingCaseMismatch::class === $class) {
|
||||
eval('namespace '.__NAMESPACE__.'; class TestingCaseMisMatch {}');
|
||||
} elseif (__NAMESPACE__.'\Fixtures\Psr4CaseMismatch' === $class) {
|
||||
return $fixtureDir.'psr4'.\DIRECTORY_SEPARATOR.'Psr4CaseMismatch.php';
|
||||
@@ -413,30 +416,30 @@ class ClassLoader
|
||||
return $fixtureDir.'notPsr0Bis.php';
|
||||
} elseif ('Symfony\Bridge\Debug\Tests\Fixtures\ExtendsDeprecatedParent' === $class) {
|
||||
eval('namespace Symfony\Bridge\Debug\Tests\Fixtures; class ExtendsDeprecatedParent extends \\'.__NAMESPACE__.'\Fixtures\DeprecatedClass {}');
|
||||
} elseif ('Test\\'.__NAMESPACE__.'\DeprecatedParentClass' === $class) {
|
||||
} elseif ('Test\\'.DeprecatedParentClass::class === $class) {
|
||||
eval('namespace Test\\'.__NAMESPACE__.'; class DeprecatedParentClass extends \\'.__NAMESPACE__.'\Fixtures\DeprecatedClass {}');
|
||||
} elseif ('Test\\'.__NAMESPACE__.'\DeprecatedInterfaceClass' === $class) {
|
||||
} elseif ('Test\\'.DeprecatedInterfaceClass::class === $class) {
|
||||
eval('namespace Test\\'.__NAMESPACE__.'; class DeprecatedInterfaceClass implements \\'.__NAMESPACE__.'\Fixtures\DeprecatedInterface {}');
|
||||
} elseif ('Test\\'.__NAMESPACE__.'\NonDeprecatedInterfaceClass' === $class) {
|
||||
} elseif ('Test\\'.NonDeprecatedInterfaceClass::class === $class) {
|
||||
eval('namespace Test\\'.__NAMESPACE__.'; class NonDeprecatedInterfaceClass implements \\'.__NAMESPACE__.'\Fixtures\NonDeprecatedInterface {}');
|
||||
} elseif ('Test\\'.__NAMESPACE__.'\Float' === $class) {
|
||||
} elseif ('Test\\'.Float::class === $class) {
|
||||
eval('namespace Test\\'.__NAMESPACE__.'; class Float {}');
|
||||
} elseif (0 === strpos($class, 'Test\\'.__NAMESPACE__.'\ExtendsFinalClass')) {
|
||||
} elseif (0 === strpos($class, 'Test\\'.ExtendsFinalClass::class)) {
|
||||
$classShortName = substr($class, strrpos($class, '\\') + 1);
|
||||
eval('namespace Test\\'.__NAMESPACE__.'; class '.$classShortName.' extends \\'.__NAMESPACE__.'\Fixtures\\'.substr($classShortName, 7).' {}');
|
||||
} elseif ('Test\\'.__NAMESPACE__.'\ExtendsAnnotatedClass' === $class) {
|
||||
} elseif ('Test\\'.ExtendsAnnotatedClass::class === $class) {
|
||||
eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsAnnotatedClass extends \\'.__NAMESPACE__.'\Fixtures\AnnotatedClass {
|
||||
public function deprecatedMethod() { }
|
||||
}');
|
||||
} elseif ('Test\\'.__NAMESPACE__.'\ExtendsInternals' === $class) {
|
||||
} elseif ('Test\\'.ExtendsInternals::class === $class) {
|
||||
eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsInternals extends ExtendsInternalsParent {
|
||||
use \\'.__NAMESPACE__.'\Fixtures\InternalTrait;
|
||||
|
||||
public function internalMethod() { }
|
||||
}');
|
||||
} elseif ('Test\\'.__NAMESPACE__.'\ExtendsInternalsParent' === $class) {
|
||||
} elseif ('Test\\'.ExtendsInternalsParent::class === $class) {
|
||||
eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsInternalsParent extends \\'.__NAMESPACE__.'\Fixtures\InternalClass implements \\'.__NAMESPACE__.'\Fixtures\InternalInterface { }');
|
||||
} elseif ('Test\\'.__NAMESPACE__.'\UseTraitWithInternalMethod' === $class) {
|
||||
} elseif ('Test\\'.UseTraitWithInternalMethod::class === $class) {
|
||||
eval('namespace Test\\'.__NAMESPACE__.'; class UseTraitWithInternalMethod { use \\'.__NAMESPACE__.'\Fixtures\TraitWithInternalMethod; }');
|
||||
}
|
||||
|
||||
|
||||
@@ -101,9 +101,14 @@ class ErrorHandlerTest extends TestCase
|
||||
$this->fail('ErrorException expected');
|
||||
} catch (\ErrorException $exception) {
|
||||
// if an exception is thrown, the test passed
|
||||
$this->assertEquals(E_NOTICE, $exception->getSeverity());
|
||||
if (\PHP_VERSION_ID < 80000) {
|
||||
$this->assertEquals(E_NOTICE, $exception->getSeverity());
|
||||
$this->assertRegExp('/^Notice: Undefined variable: (foo|bar)/', $exception->getMessage());
|
||||
} else {
|
||||
$this->assertEquals(E_WARNING, $exception->getSeverity());
|
||||
$this->assertRegExp('/^Warning: Undefined variable \$(foo|bar)/', $exception->getMessage());
|
||||
}
|
||||
$this->assertEquals(__FILE__, $exception->getFile());
|
||||
$this->assertRegExp('/^Notice: Undefined variable: (foo|bar)/', $exception->getMessage());
|
||||
|
||||
$trace = $exception->getTrace();
|
||||
|
||||
@@ -247,11 +252,17 @@ class ErrorHandlerTest extends TestCase
|
||||
|
||||
$line = null;
|
||||
$logArgCheck = function ($level, $message, $context) use (&$line) {
|
||||
$this->assertEquals('Notice: Undefined variable: undefVar', $message);
|
||||
$this->assertArrayHasKey('exception', $context);
|
||||
$exception = $context['exception'];
|
||||
|
||||
if (\PHP_VERSION_ID < 80000) {
|
||||
$this->assertEquals('Notice: Undefined variable: undefVar', $message);
|
||||
$this->assertSame(E_NOTICE, $exception->getSeverity());
|
||||
} else {
|
||||
$this->assertEquals('Warning: Undefined variable $undefVar', $message);
|
||||
$this->assertSame(E_WARNING, $exception->getSeverity());
|
||||
}
|
||||
$this->assertInstanceOf(SilencedErrorContext::class, $exception);
|
||||
$this->assertSame(E_NOTICE, $exception->getSeverity());
|
||||
$this->assertSame(__FILE__, $exception->getFile());
|
||||
$this->assertSame($line, $exception->getLine());
|
||||
$this->assertNotEmpty($exception->getTrace());
|
||||
@@ -265,8 +276,13 @@ class ErrorHandlerTest extends TestCase
|
||||
;
|
||||
|
||||
$handler = ErrorHandler::register();
|
||||
$handler->setDefaultLogger($logger, E_NOTICE);
|
||||
$handler->screamAt(E_NOTICE);
|
||||
if (\PHP_VERSION_ID < 80000) {
|
||||
$handler->setDefaultLogger($logger, E_NOTICE);
|
||||
$handler->screamAt(E_NOTICE);
|
||||
} else {
|
||||
$handler->setDefaultLogger($logger, E_WARNING);
|
||||
$handler->screamAt(E_WARNING);
|
||||
}
|
||||
unset($undefVar);
|
||||
$line = __LINE__ + 1;
|
||||
@$undefVar++;
|
||||
@@ -327,8 +343,6 @@ class ErrorHandlerTest extends TestCase
|
||||
$handler = new ErrorHandler();
|
||||
$handler->setDefaultLogger($logger);
|
||||
@$handler->handleError(E_USER_DEPRECATED, 'Foo deprecation', __FILE__, __LINE__, []);
|
||||
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -147,9 +147,9 @@ class FlattenExceptionTest extends TestCase
|
||||
|
||||
$flattened = FlattenException::create($exception)->getPrevious();
|
||||
|
||||
$this->assertEquals($flattened->getMessage(), 'Parse error: Oh noes!', 'The message is copied from the original exception.');
|
||||
$this->assertEquals($flattened->getCode(), 42, 'The code is copied from the original exception.');
|
||||
$this->assertEquals($flattened->getClass(), 'Symfony\Component\Debug\Exception\FatalThrowableError', 'The class is set to the class of the original exception');
|
||||
$this->assertEquals('Parse error: Oh noes!', $flattened->getMessage(), 'The message is copied from the original exception.');
|
||||
$this->assertEquals(42, $flattened->getCode(), 'The code is copied from the original exception.');
|
||||
$this->assertEquals('Symfony\Component\Debug\Exception\FatalThrowableError', $flattened->getClass(), 'The class is set to the class of the original exception');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -199,6 +199,10 @@ class FlattenExceptionTest extends TestCase
|
||||
|
||||
public function testArguments()
|
||||
{
|
||||
if (\PHP_VERSION_ID >= 70400) {
|
||||
$this->markTestSkipped('PHP 7.4 removes arguments from exception traces.');
|
||||
}
|
||||
|
||||
$dh = opendir(__DIR__);
|
||||
$fh = tmpfile();
|
||||
|
||||
@@ -255,12 +259,16 @@ class FlattenExceptionTest extends TestCase
|
||||
$this->assertSame(['float', INF], $array[$i++]);
|
||||
|
||||
// assertEquals() does not like NAN values.
|
||||
$this->assertEquals($array[$i][0], 'float');
|
||||
$this->assertEquals('float', $array[$i][0]);
|
||||
$this->assertNan($array[$i][1]);
|
||||
}
|
||||
|
||||
public function testRecursionInArguments()
|
||||
{
|
||||
if (\PHP_VERSION_ID >= 70400) {
|
||||
$this->markTestSkipped('PHP 7.4 removes arguments from exception traces.');
|
||||
}
|
||||
|
||||
$a = null;
|
||||
$a = ['foo', [2, &$a]];
|
||||
$exception = $this->createException($a);
|
||||
@@ -272,6 +280,10 @@ class FlattenExceptionTest extends TestCase
|
||||
|
||||
public function testTooBigArray()
|
||||
{
|
||||
if (\PHP_VERSION_ID >= 70400) {
|
||||
$this->markTestSkipped('PHP 7.4 removes arguments from exception traces.');
|
||||
}
|
||||
|
||||
$a = [];
|
||||
for ($i = 0; $i < 20; ++$i) {
|
||||
for ($j = 0; $j < 50; ++$j) {
|
||||
|
||||
@@ -29,6 +29,10 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase
|
||||
// get class loaders wrapped by DebugClassLoader
|
||||
if ($function[0] instanceof DebugClassLoader) {
|
||||
$function = $function[0]->getClassLoader();
|
||||
|
||||
if (!\is_array($function)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ($function[0] instanceof ComposerClassLoader) {
|
||||
|
||||
@@ -15,8 +15,8 @@ class ErrorHandlerThatUsesThePreviousOne
|
||||
return $handler;
|
||||
}
|
||||
|
||||
public function handleError($type, $message, $file, $line, $context)
|
||||
public function handleError()
|
||||
{
|
||||
return \call_user_func(self::$previous, $type, $message, $file, $line, $context);
|
||||
return \call_user_func_array(self::$previous, \func_get_args());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user