mirror of
https://github.com/symfony/debug.git
synced 2026-03-24 17:22:13 +01:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aeb73aca16 | ||
|
|
600aa0e19e | ||
|
|
0893a0b07c | ||
|
|
47aa9064d7 | ||
|
|
7ce874f443 | ||
|
|
bd613a9662 | ||
|
|
f34d2bf035 | ||
|
|
28f92d08bb | ||
|
|
8f904cac22 | ||
|
|
518c6a00d0 | ||
|
|
2560754c36 | ||
|
|
44897cd605 | ||
|
|
7e9cd457b4 | ||
|
|
6aa62a36bc | ||
|
|
4431584a89 | ||
|
|
346636d2ca | ||
|
|
f0ae2b4150 | ||
|
|
ce9f3b5e8e | ||
|
|
f9385709e7 | ||
|
|
ed3231ef38 | ||
|
|
a980d87a65 | ||
|
|
ef8d82f96d | ||
|
|
a99278d50a |
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1,3 +1,4 @@
|
||||
/Tests export-ignore
|
||||
/phpunit.xml.dist export-ignore
|
||||
/.gitattributes export-ignore
|
||||
/.gitignore export-ignore
|
||||
|
||||
@@ -391,7 +391,7 @@ class DebugClassLoader
|
||||
foreach ($matches as list(, $parameterType, $parameterName)) {
|
||||
if (!isset($definedParameters[$parameterName])) {
|
||||
$parameterType = trim($parameterType);
|
||||
self::$annotatedParameters[$class][$method->name][$parameterName] = sprintf('The "%%s::%s()" method will require a new "%s$%s" argument in the next major version of its parent class "%s", not defining it is deprecated.', $method->name, $parameterType ? $parameterType.' ' : '', $parameterName, $method->class);
|
||||
self::$annotatedParameters[$class][$method->name][$parameterName] = sprintf('The "%%s::%s()" method will require a new "%s$%s" argument in the next major version of its %s "%s", not defining it is deprecated.', $method->name, $parameterType ? $parameterType.' ' : '', $parameterName, interface_exists($class) ? 'interface' : 'parent class', $method->class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,14 +226,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];
|
||||
|
||||
@@ -403,19 +403,7 @@ class ErrorHandler
|
||||
}
|
||||
$scope = $this->scopedErrors & $type;
|
||||
|
||||
if (4 < $numArgs = \func_num_args()) {
|
||||
$context = $scope ? (func_get_arg(4) ?: []) : [];
|
||||
} else {
|
||||
$context = [];
|
||||
}
|
||||
|
||||
if (isset($context['GLOBALS']) && $scope) {
|
||||
$e = $context; // Whatever the signature of the method,
|
||||
unset($e['GLOBALS'], $context); // $context is always a reference in 5.3
|
||||
$context = $e;
|
||||
}
|
||||
|
||||
if (false !== strpos($message, "class@anonymous\0")) {
|
||||
if (false !== strpos($message, "@anonymous\0")) {
|
||||
$logMessage = $this->levels[$type].': '.(new FlattenException())->setMessage($message)->getMessage();
|
||||
} else {
|
||||
$logMessage = $this->levels[$type].': '.$message;
|
||||
@@ -476,6 +464,8 @@ class ErrorHandler
|
||||
// `return trigger_error($e, E_USER_ERROR);` allows this error handler
|
||||
// to make $e get through the __toString() barrier.
|
||||
|
||||
$context = 4 < \func_num_args() ? (func_get_arg(4) ?: []) : [];
|
||||
|
||||
foreach ($context as $e) {
|
||||
if ($e instanceof \Throwable && $e->__toString() === $message) {
|
||||
self::$toStringException = $e;
|
||||
@@ -499,7 +489,7 @@ class ErrorHandler
|
||||
if ($this->isRecursive) {
|
||||
$log = 0;
|
||||
} 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();
|
||||
}
|
||||
@@ -511,7 +501,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);
|
||||
}
|
||||
}
|
||||
@@ -540,7 +530,7 @@ class ErrorHandler
|
||||
$handlerException = null;
|
||||
|
||||
if (($this->loggedErrors & $type) || $exception instanceof FatalThrowableError) {
|
||||
if (false !== strpos($message = $exception->getMessage(), "class@anonymous\0")) {
|
||||
if (false !== strpos($message = $exception->getMessage(), "@anonymous\0")) {
|
||||
$message = (new FlattenException())->setMessage($message)->getMessage();
|
||||
}
|
||||
if ($exception instanceof FatalErrorException) {
|
||||
|
||||
@@ -26,7 +26,7 @@ class FatalThrowableError extends FatalErrorException
|
||||
|
||||
public function __construct(\Throwable $e)
|
||||
{
|
||||
$this->originalClassName = \get_class($e);
|
||||
$this->originalClassName = get_debug_type($e);
|
||||
|
||||
if ($e instanceof \ParseError) {
|
||||
$severity = E_PARSE;
|
||||
|
||||
@@ -67,7 +67,7 @@ class FlattenException
|
||||
$e->setStatusCode($statusCode);
|
||||
$e->setHeaders($headers);
|
||||
$e->setTraceFromThrowable($exception);
|
||||
$e->setClass($exception instanceof FatalThrowableError ? $exception->getOriginalClassName() : \get_class($exception));
|
||||
$e->setClass($exception instanceof FatalThrowableError ? $exception->getOriginalClassName() : get_debug_type($exception));
|
||||
$e->setFile($exception->getFile());
|
||||
$e->setLine($exception->getLine());
|
||||
|
||||
@@ -134,7 +134,7 @@ class FlattenException
|
||||
*/
|
||||
public function setClass($class)
|
||||
{
|
||||
$this->class = 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class;
|
||||
$this->class = false !== strpos($class, "@anonymous\0") ? (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous' : $class;
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -179,9 +179,9 @@ class FlattenException
|
||||
*/
|
||||
public function setMessage($message)
|
||||
{
|
||||
if (false !== strpos($message, "class@anonymous\0")) {
|
||||
$message = preg_replace_callback('/class@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', function ($m) {
|
||||
return class_exists($m[0], false) ? get_parent_class($m[0]).'@anonymous' : $m[0];
|
||||
if (false !== strpos($message, "@anonymous\0")) {
|
||||
$message = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', function ($m) {
|
||||
return class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0];
|
||||
}, $message);
|
||||
}
|
||||
|
||||
|
||||
13
README.md
13
README.md
@@ -8,6 +8,19 @@ 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
|
||||
---------
|
||||
|
||||
|
||||
@@ -292,12 +292,12 @@ class DebugClassLoaderTest extends TestCase
|
||||
|
||||
$this->assertSame([
|
||||
'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::quzMethod()" method will require a new "Quz $quz" argument in the next major version of its parent class "Symfony\Component\Debug\Tests\Fixtures\ClassWithAnnotatedParameters", not defining it is deprecated.',
|
||||
'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::whereAmI()" method will require a new "bool $matrix" argument in the next major version of its parent class "Symfony\Component\Debug\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
|
||||
'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "$noType" argument in the next major version of its parent class "Symfony\Component\Debug\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
|
||||
'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "callable(\Throwable|null $reason, mixed $value) $callback" argument in the next major version of its parent class "Symfony\Component\Debug\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
|
||||
'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "string $param" argument in the next major version of its parent class "Symfony\Component\Debug\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
|
||||
'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "callable ($a, $b) $anotherOne" argument in the next major version of its parent class "Symfony\Component\Debug\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
|
||||
'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "Type$WithDollarIsStillAType $ccc" argument in the next major version of its parent class "Symfony\Component\Debug\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
|
||||
'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::whereAmI()" method will require a new "bool $matrix" argument in the next major version of its interface "Symfony\Component\Debug\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
|
||||
'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "$noType" argument in the next major version of its interface "Symfony\Component\Debug\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
|
||||
'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "callable(\Throwable|null $reason, mixed $value) $callback" argument in the next major version of its interface "Symfony\Component\Debug\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
|
||||
'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "string $param" argument in the next major version of its interface "Symfony\Component\Debug\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
|
||||
'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "callable ($a, $b) $anotherOne" argument in the next major version of its interface "Symfony\Component\Debug\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
|
||||
'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "Type$WithDollarIsStillAType $ccc" argument in the next major version of its interface "Symfony\Component\Debug\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
|
||||
'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::isSymfony()" method will require a new "true $yes" argument in the next major version of its parent class "Symfony\Component\Debug\Tests\Fixtures\ClassWithAnnotatedParameters", not defining it is deprecated.',
|
||||
], $deprecations);
|
||||
}
|
||||
|
||||
@@ -103,9 +103,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->assertMatchesRegularExpression('/^Notice: Undefined variable: (foo|bar)/', $exception->getMessage());
|
||||
} else {
|
||||
$this->assertEquals(E_WARNING, $exception->getSeverity());
|
||||
$this->assertMatchesRegularExpression('/^Warning: Undefined variable \$(foo|bar)/', $exception->getMessage());
|
||||
}
|
||||
$this->assertEquals(__FILE__, $exception->getFile());
|
||||
$this->assertRegExp('/^Notice: Undefined variable: (foo|bar)/', $exception->getMessage());
|
||||
|
||||
$trace = $exception->getTrace();
|
||||
|
||||
@@ -249,11 +254,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());
|
||||
@@ -267,8 +278,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++;
|
||||
@@ -309,6 +325,26 @@ class ErrorHandlerTest extends TestCase
|
||||
}
|
||||
}
|
||||
|
||||
public function testHandleErrorWithAnonymousClass()
|
||||
{
|
||||
$handler = ErrorHandler::register();
|
||||
$handler->throwAt(E_USER_WARNING, true);
|
||||
try {
|
||||
$handler->handleError(E_USER_WARNING, 'foo '.\get_class(new class() extends \stdClass {
|
||||
}).' bar', 'foo.php', 12);
|
||||
$this->fail('Exception expected.');
|
||||
} catch (\ErrorException $e) {
|
||||
} finally {
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
}
|
||||
|
||||
$this->assertSame('User Warning: foo stdClass@anonymous bar', $e->getMessage());
|
||||
$this->assertSame(E_USER_WARNING, $e->getSeverity());
|
||||
$this->assertSame('foo.php', $e->getFile());
|
||||
$this->assertSame(12, $e->getLine());
|
||||
}
|
||||
|
||||
public function testHandleDeprecation()
|
||||
{
|
||||
$logArgCheck = function ($level, $message, $context) {
|
||||
@@ -329,8 +365,6 @@ class ErrorHandlerTest extends TestCase
|
||||
$handler = new ErrorHandler();
|
||||
$handler->setDefaultLogger($logger);
|
||||
@$handler->handleError(E_USER_DEPRECATED, 'Foo deprecation', __FILE__, __LINE__, []);
|
||||
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
public function testHandleException()
|
||||
|
||||
@@ -174,9 +174,9 @@ class FlattenExceptionTest extends TestCase
|
||||
|
||||
$flattened = FlattenException::create($exception)->getPrevious();
|
||||
|
||||
$this->assertEquals($flattened->getMessage(), '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(), 'ParseError', 'The class is set to the class of the original exception');
|
||||
$this->assertEquals('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('ParseError', $flattened->getClass(), 'The class is set to the class of the original exception');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -300,7 +300,7 @@ 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]);
|
||||
}
|
||||
|
||||
@@ -355,6 +355,11 @@ class FlattenExceptionTest extends TestCase
|
||||
|
||||
$this->assertSame('RuntimeException@anonymous', $flattened->getClass());
|
||||
|
||||
$flattened->setClass(\get_class(new class('Oops') extends NotFoundHttpException {
|
||||
}));
|
||||
|
||||
$this->assertSame('Symfony\Component\HttpKernel\Exception\NotFoundHttpException@anonymous', $flattened->getClass());
|
||||
|
||||
$flattened = FlattenException::create(new \Exception(sprintf('Class "%s" blah.', \get_class(new class() extends \RuntimeException {
|
||||
}))));
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase
|
||||
}
|
||||
|
||||
$this->assertInstanceOf('Symfony\Component\Debug\Exception\ClassNotFoundException', $exception);
|
||||
$this->assertSame($translatedMessage, $exception->getMessage());
|
||||
$this->assertEquals($translatedMessage, $exception->getMessage());
|
||||
$this->assertSame($error['type'], $exception->getSeverity());
|
||||
$this->assertSame($error['file'], $exception->getFile());
|
||||
$this->assertSame($error['line'], $exception->getLine());
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,9 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^7.1.3",
|
||||
"psr/log": "~1.0"
|
||||
"php": ">=7.1.3",
|
||||
"psr/log": "~1.0",
|
||||
"symfony/polyfill-php80": "^1.15"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/http-kernel": "<3.4"
|
||||
|
||||
@@ -14,10 +14,7 @@
|
||||
|
||||
<testsuites>
|
||||
<testsuite name="Symfony Debug Component Test Suite">
|
||||
<directory>./Tests/</directory>
|
||||
</testsuite>
|
||||
<testsuite name="Symfony Debug Extension Test Suite">
|
||||
<directory suffix=".phpt">./Resources/ext/tests/</directory>
|
||||
<directory suffix=".phpt">./Tests/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user