From 29da1bc5330facdb7473e9997573d98f9c604265 Mon Sep 17 00:00:00 2001 From: tigitz Date: Fri, 30 Sep 2022 23:29:24 +0200 Subject: [PATCH 01/90] Leverage class name literal on object --- Tests/Caster/ExceptionCasterTest.php | 4 ++-- Tests/Caster/StubCasterTest.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Tests/Caster/ExceptionCasterTest.php b/Tests/Caster/ExceptionCasterTest.php index 7de30f4f..73545701 100644 --- a/Tests/Caster/ExceptionCasterTest.php +++ b/Tests/Caster/ExceptionCasterTest.php @@ -251,8 +251,8 @@ public function testExcludeVerbosity() public function testAnonymous() { - $e = new \Exception(sprintf('Boo "%s" ba.', \get_class(new class('Foo') extends \Exception { - }))); + $e = new \Exception(sprintf('Boo "%s" ba.', (new class('Foo') extends \Exception { + })::class)); $expectedDump = <<<'EODUMP' Exception { diff --git a/Tests/Caster/StubCasterTest.php b/Tests/Caster/StubCasterTest.php index cd6876cd..6ca2dad3 100644 --- a/Tests/Caster/StubCasterTest.php +++ b/Tests/Caster/StubCasterTest.php @@ -192,8 +192,8 @@ public function testClassStubWithNotExistingMethod() public function testClassStubWithAnonymousClass() { - $var = [new ClassStub(\get_class(new class() extends \Exception { - }))]; + $var = [new ClassStub((new class() extends \Exception { + })::class)]; $cloner = new VarCloner(); $dumper = new HtmlDumper(); From 5635a6276fcd86ed59f2cb3f86050e356c4a893a Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 2 Dec 2022 22:43:20 +0100 Subject: [PATCH 02/90] [VarDumper] Add caster for WeakMap --- CHANGELOG.md | 5 +++++ Caster/SplCaster.php | 22 ++++++++++++++++++++-- Cloner/AbstractCloner.php | 1 + Tests/Caster/SplCasterTest.php | 20 ++++++++++++++++++++ 4 files changed, 46 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ffa4daf2..97204fc6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +6.3 +--- + + * Add caster for `WeakMap` + 6.2 --- diff --git a/Caster/SplCaster.php b/Caster/SplCaster.php index 448afbad..72ac5dce 100644 --- a/Caster/SplCaster.php +++ b/Caster/SplCaster.php @@ -184,10 +184,10 @@ public static function castObjectStorage(\SplObjectStorage $c, array $a, Stub $s $clone = clone $c; foreach ($clone as $obj) { - $storage[] = [ + $storage[] = new EnumStub([ 'object' => $obj, 'info' => $clone->getInfo(), - ]; + ]); } $a += [ @@ -211,6 +211,24 @@ public static function castWeakReference(\WeakReference $c, array $a, Stub $stub return $a; } + public static function castWeakMap(\WeakMap $c, array $a, Stub $stub, bool $isNested) + { + $map = []; + + foreach (clone $c as $obj => $data) { + $map[] = new EnumStub([ + 'object' => $obj, + 'data' => $data, + ]); + } + + $a += [ + Caster::PREFIX_VIRTUAL.'map' => $map, + ]; + + return $a; + } + private static function castSplArray(\ArrayObject|\ArrayIterator $c, array $a, Stub $stub, bool $isNested): array { $prefix = Caster::PREFIX_VIRTUAL; diff --git a/Cloner/AbstractCloner.php b/Cloner/AbstractCloner.php index c722a8e9..3b92fad0 100644 --- a/Cloner/AbstractCloner.php +++ b/Cloner/AbstractCloner.php @@ -124,6 +124,7 @@ abstract class AbstractCloner implements ClonerInterface 'SplObjectStorage' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castObjectStorage'], 'SplPriorityQueue' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castHeap'], 'OuterIterator' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castOuterIterator'], + 'WeakMap' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castWeakMap'], 'WeakReference' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castWeakReference'], 'Redis' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedis'], diff --git a/Tests/Caster/SplCasterTest.php b/Tests/Caster/SplCasterTest.php index 26887b13..ed93bfc4 100644 --- a/Tests/Caster/SplCasterTest.php +++ b/Tests/Caster/SplCasterTest.php @@ -213,6 +213,26 @@ public function testBadSplFileInfo() EOTXT; $this->assertDumpEquals($expected, $var); } + + public function testWeakMap() + { + $var = new \WeakMap(); + $obj = new \stdClass(); + $var[$obj] = 123; + + $expected = << { + object: {} + data: 123 + } + ] + } + EOTXT; + + $this->assertDumpEquals($expected, $var); + } } class MyArrayIterator extends \ArrayIterator From 422e4a6f42e623092161d34ebfbb2aff7ca1cc27 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Sun, 11 Dec 2022 11:50:52 +0100 Subject: [PATCH 03/90] Update types for dd() --- Resources/functions/dump.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Resources/functions/dump.php b/Resources/functions/dump.php index 6221a4d1..978a012f 100644 --- a/Resources/functions/dump.php +++ b/Resources/functions/dump.php @@ -32,10 +32,7 @@ function dump(mixed $var, mixed ...$moreVars): mixed } if (!function_exists('dd')) { - /** - * @return never - */ - function dd(...$vars): void + function dd(mixed ...$vars): never { if (!in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) && !headers_sent()) { header('HTTP/1.1 500 Internal Server Error'); From 0d0fa05f2567a41e5b43a2b420658887d7da6b50 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Thu, 1 Dec 2022 18:32:26 +0100 Subject: [PATCH 04/90] [VarDumper] Add support of named arguments to `dd()` and `dump()` to display the argument name --- CHANGELOG.md | 1 + Caster/ScalarStub.php | 27 +++++++++++++++++++++ Caster/StubCaster.php | 8 ++++++ Cloner/AbstractCloner.php | 1 + Cloner/Data.php | 12 ++++++++- Cloner/Stub.php | 1 + Dumper/ContextualizedDumper.php | 2 +- Resources/functions/dump.php | 33 ++++++++++++++++++------- Tests/Caster/StubCasterTest.php | 16 +++++++++++- Tests/Dumper/FunctionsTest.php | 43 +++++++++++++++++++++++++++++++-- VarDumper.php | 18 +++++++++++--- 11 files changed, 144 insertions(+), 18 deletions(-) create mode 100644 Caster/ScalarStub.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 97204fc6..c5abeee3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG --- * Add caster for `WeakMap` + * Add support of named arguments to `dd()` and `dump()` to display the argument name 6.2 --- diff --git a/Caster/ScalarStub.php b/Caster/ScalarStub.php new file mode 100644 index 00000000..3bb1935b --- /dev/null +++ b/Caster/ScalarStub.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Represents any arbitrary value. + * + * @author Alexandre Daubois + */ +class ScalarStub extends Stub +{ + public function __construct(mixed $value) + { + $this->value = $value; + } +} diff --git a/Caster/StubCaster.php b/Caster/StubCaster.php index 32ead7c2..9318ad1f 100644 --- a/Caster/StubCaster.php +++ b/Caster/StubCaster.php @@ -81,4 +81,12 @@ public static function castEnum(EnumStub $c, array $a, Stub $stub, bool $isNeste return $a; } + + public static function castScalar(ScalarStub $scalarStub, array $a, Stub $stub) + { + $stub->type = Stub::TYPE_SCALAR; + $stub->attr['value'] = $scalarStub->value; + + return $a; + } } diff --git a/Cloner/AbstractCloner.php b/Cloner/AbstractCloner.php index b7220258..bcd30137 100644 --- a/Cloner/AbstractCloner.php +++ b/Cloner/AbstractCloner.php @@ -28,6 +28,7 @@ abstract class AbstractCloner implements ClonerInterface 'Symfony\Component\VarDumper\Caster\CutArrayStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castCutArray'], 'Symfony\Component\VarDumper\Caster\ConstStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castStub'], 'Symfony\Component\VarDumper\Caster\EnumStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castEnum'], + 'Symfony\Component\VarDumper\Caster\ScalarStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castScalar'], 'Fiber' => ['Symfony\Component\VarDumper\Caster\FiberCaster', 'castFiber'], diff --git a/Cloner/Data.php b/Cloner/Data.php index 6ecb883e..d87d5690 100644 --- a/Cloner/Data.php +++ b/Cloner/Data.php @@ -211,6 +211,11 @@ public function withContext(array $context): static return $data; } + public function getContext(): array + { + return $this->context; + } + /** * Seeks to a specific key in nested data structures. */ @@ -262,11 +267,12 @@ public function dump(DumperInterface $dumper) { $refs = [0]; $cursor = new Cursor(); + $label = $this->context['label'] ?? ''; if ($cursor->attr = $this->context[SourceContextProvider::class] ?? []) { $cursor->attr['if_links'] = true; $cursor->hashType = -1; - $dumper->dumpScalar($cursor, 'default', '^'); + $dumper->dumpScalar($cursor, 'default', $label.'^'); $cursor->attr = ['if_links' => true]; $dumper->dumpScalar($cursor, 'default', ' '); $cursor->hashType = 0; @@ -362,6 +368,10 @@ private function dumpItem(DumperInterface $dumper, Cursor $cursor, array &$refs, $dumper->leaveHash($cursor, $item->type, $item->class, $withChildren, $cut); break; + case Stub::TYPE_SCALAR: + $dumper->dumpScalar($cursor, 'default', $item->attr['value']); + break; + default: throw new \RuntimeException(sprintf('Unexpected Stub type: "%s".', $item->type)); } diff --git a/Cloner/Stub.php b/Cloner/Stub.php index 1c5b8871..0c2a4b9d 100644 --- a/Cloner/Stub.php +++ b/Cloner/Stub.php @@ -23,6 +23,7 @@ class Stub public const TYPE_ARRAY = 3; public const TYPE_OBJECT = 4; public const TYPE_RESOURCE = 5; + public const TYPE_SCALAR = 6; public const STRING_BINARY = 1; public const STRING_UTF8 = 2; diff --git a/Dumper/ContextualizedDumper.php b/Dumper/ContextualizedDumper.php index 1ba803d8..c10cd444 100644 --- a/Dumper/ContextualizedDumper.php +++ b/Dumper/ContextualizedDumper.php @@ -33,7 +33,7 @@ public function __construct(DataDumperInterface $wrappedDumper, array $contextPr public function dump(Data $data) { - $context = []; + $context = $data->getContext(); foreach ($this->contextProviders as $contextProvider) { $context[$contextProvider::class] = $contextProvider->getContext(); } diff --git a/Resources/functions/dump.php b/Resources/functions/dump.php index 6221a4d1..4e7652c4 100644 --- a/Resources/functions/dump.php +++ b/Resources/functions/dump.php @@ -9,25 +9,36 @@ * file that was distributed with this source code. */ +use Symfony\Component\VarDumper\Caster\ScalarStub; use Symfony\Component\VarDumper\VarDumper; if (!function_exists('dump')) { /** * @author Nicolas Grekas + * @author Alexandre Daubois */ - function dump(mixed $var, mixed ...$moreVars): mixed + function dump(mixed ...$vars): mixed { - VarDumper::dump($var); + if (!$vars) { + VarDumper::dump(new ScalarStub('🐛')); - foreach ($moreVars as $v) { - VarDumper::dump($v); + return null; } - if (1 < func_num_args()) { - return func_get_args(); + if (isset($vars[0]) && 1 === count($vars)) { + VarDumper::dump($vars[0]); + $k = 0; + } else { + foreach ($vars as $k => $v) { + VarDumper::dump($v, is_int($k) ? 1 + $k : $k); + } } - return $var; + if (1 < count($vars)) { + return $vars; + } + + return $vars[$k]; } } @@ -41,8 +52,12 @@ function dd(...$vars): void header('HTTP/1.1 500 Internal Server Error'); } - foreach ($vars as $v) { - VarDumper::dump($v); + if (isset($vars[0]) && 1 === count($vars)) { + VarDumper::dump($vars[0]); + } else { + foreach ($vars as $k => $v) { + VarDumper::dump($v, is_int($k) ? 1 + $k : $k); + } } exit(1); diff --git a/Tests/Caster/StubCasterTest.php b/Tests/Caster/StubCasterTest.php index 6ca2dad3..8b3e12b5 100644 --- a/Tests/Caster/StubCasterTest.php +++ b/Tests/Caster/StubCasterTest.php @@ -15,6 +15,7 @@ use Symfony\Component\VarDumper\Caster\ArgsStub; use Symfony\Component\VarDumper\Caster\ClassStub; use Symfony\Component\VarDumper\Caster\LinkStub; +use Symfony\Component\VarDumper\Caster\ScalarStub; use Symfony\Component\VarDumper\Cloner\VarCloner; use Symfony\Component\VarDumper\Dumper\HtmlDumper; use Symfony\Component\VarDumper\Test\VarDumperTestTrait; @@ -87,6 +88,19 @@ public function testArgsStubWithClosure() $this->assertDumpMatchesFormat($expectedDump, $args); } + public function testEmptyStub() + { + $args = [new ScalarStub('🐛')]; + + $expectedDump = <<<'EODUMP' +array:1 [ + 0 => 🐛 +] +EODUMP; + + $this->assertDumpMatchesFormat($expectedDump, $args); + } + public function testLinkStub() { $var = [new LinkStub(__CLASS__, 0, __FILE__)]; @@ -203,7 +217,7 @@ public function testClassStubWithAnonymousClass() $expectedDump = <<<'EODUMP' array:1 [ - 0 => "Exception@anonymous" + 0 => "Exception@anonymous" ] EODUMP; diff --git a/Tests/Dumper/FunctionsTest.php b/Tests/Dumper/FunctionsTest.php index 7444d4bf..d158d7eb 100644 --- a/Tests/Dumper/FunctionsTest.php +++ b/Tests/Dumper/FunctionsTest.php @@ -18,6 +18,17 @@ class FunctionsTest extends TestCase { + public function testDumpWithoutArg() + { + $this->setupVarDumper(); + + ob_start(); + $return = dump(); + ob_end_clean(); + + $this->assertNull($return); + } + public function testDumpReturnsFirstArg() { $this->setupVarDumper(); @@ -28,7 +39,20 @@ public function testDumpReturnsFirstArg() $return = dump($var1); ob_end_clean(); - $this->assertEquals($var1, $return); + $this->assertSame($var1, $return); + } + + public function testDumpReturnsFirstNamedArgWithoutSectionName() + { + $this->setupVarDumper(); + + $var1 = 'a'; + + ob_start(); + $return = dump(first: $var1); + ob_end_clean(); + + $this->assertSame($var1, $return); } public function testDumpReturnsAllArgsInArray() @@ -43,7 +67,22 @@ public function testDumpReturnsAllArgsInArray() $return = dump($var1, $var2, $var3); ob_end_clean(); - $this->assertEquals([$var1, $var2, $var3], $return); + $this->assertSame([$var1, $var2, $var3], $return); + } + + public function testDumpReturnsAllNamedArgsInArray() + { + $this->setupVarDumper(); + + $var1 = 'a'; + $var2 = 'b'; + $var3 = 'c'; + + ob_start(); + $return = dump($var1, second: $var2, third: $var3); + ob_end_clean(); + + $this->assertSame([$var1, 'second' => $var2, 'third' => $var3], $return); } protected function setupVarDumper() diff --git a/VarDumper.php b/VarDumper.php index 840bfd64..7c160166 100644 --- a/VarDumper.php +++ b/VarDumper.php @@ -37,13 +37,17 @@ class VarDumper */ private static $handler; - public static function dump(mixed $var) + /** + * @param string|null $label + */ + public static function dump(mixed $var/* , string $label = null */) { + $label = 2 <= \func_num_args() ? func_get_arg(1) : null; if (null === self::$handler) { self::register(); } - return (self::$handler)($var); + return (self::$handler)($var, $label); } public static function setHandler(callable $callable = null): ?callable @@ -90,8 +94,14 @@ private static function register(): void $dumper = new ContextualizedDumper($dumper, [new SourceContextProvider()]); } - self::$handler = function ($var) use ($cloner, $dumper) { - $dumper->dump($cloner->cloneVar($var)); + self::$handler = function ($var, string $label = null) use ($cloner, $dumper) { + $var = $cloner->cloneVar($var); + + if (null !== $label) { + $var = $var->withContext(['label' => $label]); + } + + $dumper->dump($var); }; } From 6358546f930d4f81b2003392b1749820bc005a22 Mon Sep 17 00:00:00 2001 From: tigitz Date: Sun, 1 Jan 2023 19:45:34 +0100 Subject: [PATCH 05/90] Leverage arrow function syntax for closure --- Caster/ClassStub.php | 4 +--- Caster/ExceptionCaster.php | 4 +--- Tests/Cloner/VarClonerTest.php | 4 +--- Tests/Command/Descriptor/CliDescriptorTest.php | 4 +--- 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/Caster/ClassStub.php b/Caster/ClassStub.php index fb8377a0..f27a17ce 100644 --- a/Caster/ClassStub.php +++ b/Caster/ClassStub.php @@ -56,9 +56,7 @@ public function __construct(string $identifier, callable|array|string $callable } if (str_contains($identifier, "@anonymous\0")) { - $this->value = $identifier = 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]; - }, $identifier); + $this->value = $identifier = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', fn ($m) => class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0], $identifier); } if (null !== $callable && $r instanceof \ReflectionFunctionAbstract) { diff --git a/Caster/ExceptionCaster.php b/Caster/ExceptionCaster.php index 14caf71f..80a91ead 100644 --- a/Caster/ExceptionCaster.php +++ b/Caster/ExceptionCaster.php @@ -288,9 +288,7 @@ private static function filterExceptionArray(string $xClass, array $a, string $x unset($a[$xPrefix.'string'], $a[Caster::PREFIX_DYNAMIC.'xdebug_message'], $a[Caster::PREFIX_DYNAMIC.'__destructorException']); if (isset($a[Caster::PREFIX_PROTECTED.'message']) && str_contains($a[Caster::PREFIX_PROTECTED.'message'], "@anonymous\0")) { - $a[Caster::PREFIX_PROTECTED.'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]; - }, $a[Caster::PREFIX_PROTECTED.'message']); + $a[Caster::PREFIX_PROTECTED.'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]++/', fn ($m) => class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0], $a[Caster::PREFIX_PROTECTED.'message']); } if (isset($a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line'])) { diff --git a/Tests/Cloner/VarClonerTest.php b/Tests/Cloner/VarClonerTest.php index 36639ca9..ad179699 100644 --- a/Tests/Cloner/VarClonerTest.php +++ b/Tests/Cloner/VarClonerTest.php @@ -399,9 +399,7 @@ public function testJsonCast() public function testCaster() { $cloner = new VarCloner([ - '*' => function ($obj, $array) { - return ['foo' => 123]; - }, + '*' => fn ($obj, $array) => ['foo' => 123], __CLASS__ => function ($obj, $array) { ++$array['foo']; diff --git a/Tests/Command/Descriptor/CliDescriptorTest.php b/Tests/Command/Descriptor/CliDescriptorTest.php index 56fb2187..6b1f5430 100644 --- a/Tests/Command/Descriptor/CliDescriptorTest.php +++ b/Tests/Command/Descriptor/CliDescriptorTest.php @@ -45,9 +45,7 @@ public function testDescribe(array $context, string $expectedOutput, bool $decor { $output = new BufferedOutput(); $output->setDecorated($decorated); - $descriptor = new CliDescriptor(new CliDumper(function ($s) { - return $s; - })); + $descriptor = new CliDescriptor(new CliDumper(fn ($s) => $s)); $descriptor->describe($output, new Data([[123]]), $context + ['timestamp' => 1544804268.3668], 1); From e169dd4c494c6a2a1c8314bf929f385e64bcc249 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Ostroluck=C3=BD?= Date: Sun, 18 Dec 2022 15:47:23 +0100 Subject: [PATCH 06/90] [VarDumper] Add Relay support --- CHANGELOG.md | 1 + Caster/RedisCaster.php | 23 ++++++++++++----------- Cloner/AbstractCloner.php | 1 + Tests/Caster/RedisCasterTest.php | 22 ++++++++++++++++------ 4 files changed, 30 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5abeee3..3b29f419 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * Add caster for `WeakMap` * Add support of named arguments to `dd()` and `dump()` to display the argument name + * Add support for `Relay\Relay` 6.2 --- diff --git a/Caster/RedisCaster.php b/Caster/RedisCaster.php index eac25a12..f88c72a4 100644 --- a/Caster/RedisCaster.php +++ b/Caster/RedisCaster.php @@ -11,6 +11,7 @@ namespace Symfony\Component\VarDumper\Caster; +use Relay\Relay; use Symfony\Component\VarDumper\Cloner\Stub; /** @@ -23,15 +24,15 @@ class RedisCaster { private const SERIALIZERS = [ - \Redis::SERIALIZER_NONE => 'NONE', - \Redis::SERIALIZER_PHP => 'PHP', + 0 => 'NONE', // Redis::SERIALIZER_NONE + 1 => 'PHP', // Redis::SERIALIZER_PHP 2 => 'IGBINARY', // Optional Redis::SERIALIZER_IGBINARY ]; private const MODES = [ - \Redis::ATOMIC => 'ATOMIC', - \Redis::MULTI => 'MULTI', - \Redis::PIPELINE => 'PIPELINE', + 0 => 'ATOMIC', // Redis::ATOMIC + 1 => 'MULTI', // Redis::MULTI + 2 => 'PIPELINE', // Redis::PIPELINE ]; private const COMPRESSION_MODES = [ @@ -46,7 +47,7 @@ class RedisCaster \RedisCluster::FAILOVER_DISTRIBUTE_SLAVES => 'DISTRIBUTE_SLAVES', ]; - public static function castRedis(\Redis $c, array $a, Stub $stub, bool $isNested) + public static function castRedis(\Redis|Relay $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; @@ -102,9 +103,9 @@ public static function castRedisCluster(\RedisCluster $c, array $a, Stub $stub, return $a; } - private static function getRedisOptions(\Redis|\RedisArray|\RedisCluster $redis, array $options = []): EnumStub + private static function getRedisOptions(\Redis|Relay|\RedisArray|\RedisCluster $redis, array $options = []): EnumStub { - $serializer = $redis->getOption(\Redis::OPT_SERIALIZER); + $serializer = $redis->getOption(\defined('Redis::OPT_SERIALIZER') ? \Redis::OPT_SERIALIZER : 1); if (\is_array($serializer)) { foreach ($serializer as &$v) { if (isset(self::SERIALIZERS[$v])) { @@ -136,11 +137,11 @@ private static function getRedisOptions(\Redis|\RedisArray|\RedisCluster $redis, } $options += [ - 'TCP_KEEPALIVE' => \defined('Redis::OPT_TCP_KEEPALIVE') ? $redis->getOption(\Redis::OPT_TCP_KEEPALIVE) : 0, - 'READ_TIMEOUT' => $redis->getOption(\Redis::OPT_READ_TIMEOUT), + 'TCP_KEEPALIVE' => \defined('Redis::OPT_TCP_KEEPALIVE') ? $redis->getOption(\Redis::OPT_TCP_KEEPALIVE) : Relay::OPT_TCP_KEEPALIVE, + 'READ_TIMEOUT' => $redis->getOption(\defined('Redis::OPT_READ_TIMEOUT') ? \Redis::OPT_READ_TIMEOUT : Relay::OPT_READ_TIMEOUT), 'COMPRESSION' => $compression, 'SERIALIZER' => $serializer, - 'PREFIX' => $redis->getOption(\Redis::OPT_PREFIX), + 'PREFIX' => $redis->getOption(\defined('Redis::OPT_PREFIX') ? \Redis::OPT_PREFIX : Relay::OPT_PREFIX), 'SCAN' => $retry, ]; diff --git a/Cloner/AbstractCloner.php b/Cloner/AbstractCloner.php index bcd30137..599c59ec 100644 --- a/Cloner/AbstractCloner.php +++ b/Cloner/AbstractCloner.php @@ -130,6 +130,7 @@ abstract class AbstractCloner implements ClonerInterface 'WeakReference' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castWeakReference'], 'Redis' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedis'], + 'Relay\Relay' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedis'], 'RedisArray' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedisArray'], 'RedisCluster' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedisCluster'], diff --git a/Tests/Caster/RedisCasterTest.php b/Tests/Caster/RedisCasterTest.php index 058b95d0..3d56584a 100644 --- a/Tests/Caster/RedisCasterTest.php +++ b/Tests/Caster/RedisCasterTest.php @@ -16,13 +16,15 @@ /** * @author Nicolas Grekas - * @requires extension redis * @group integration */ class RedisCasterTest extends TestCase { use VarDumperTestTrait; + /** + * @requires extension redis + */ public function testNotConnected() { $redis = new \Redis(); @@ -36,10 +38,18 @@ public function testNotConnected() $this->assertDumpMatchesFormat($xCast, $redis); } - public function testConnected() + /** + * @testWith ["Redis"] + * ["Relay\\Relay"] + */ + public function testConnected(string $class) { + if (!class_exists($class)) { + self::markTestSkipped(sprintf('"%s" class required', $class)); + } + $redisHost = explode(':', getenv('REDIS_HOST')) + [1 => 6379]; - $redis = new \Redis(); + $redis = new $class; try { $redis->connect(...$redisHost); } catch (\Exception $e) { @@ -47,7 +57,7 @@ public function testConnected() } $xCast = << Date: Wed, 21 Dec 2022 22:37:25 +0100 Subject: [PATCH 07/90] [VarDumper] Display invisible characters --- CHANGELOG.md | 1 + Dumper/CliDumper.php | 9 +++++++++ Dumper/HtmlDumper.php | 8 +++++++- Tests/Dumper/CliDumperTest.php | 3 ++- Tests/Dumper/HtmlDumperTest.php | 3 ++- Tests/Fixtures/dumb-var.php | 13 +++++++++++-- 6 files changed, 32 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b29f419..93298750 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ CHANGELOG * Add caster for `WeakMap` * Add support of named arguments to `dd()` and `dump()` to display the argument name * Add support for `Relay\Relay` + * Add display of invisible characters 6.2 --- diff --git a/Dumper/CliDumper.php b/Dumper/CliDumper.php index c52ac4db..7d6810e4 100644 --- a/Dumper/CliDumper.php +++ b/Dumper/CliDumper.php @@ -51,6 +51,7 @@ class CliDumper extends AbstractDumper "\r" => '\r', "\033" => '\e', ]; + protected static $unicodeCharsRx = "/[\u{00A0}\u{00AD}\u{034F}\u{061C}\u{115F}\u{1160}\u{17B4}\u{17B5}\u{180E}\u{2000}-\u{200F}\u{202F}\u{205F}\u{2060}-\u{2064}\u{206A}-\u{206F}\u{3000}\u{2800}\u{3164}\u{FEFF}\u{FFA0}\u{1D159}\u{1D173}-\u{1D17A}]/u"; protected $collapseNextHash = false; protected $expandNextHash = false; @@ -450,6 +451,14 @@ protected function style(string $style, string $value, array $attr = []): string return $s.$endCchr; }, $value, -1, $cchrCount); + if (!($attr['binary'] ?? false)) { + $value = preg_replace_callback(static::$unicodeCharsRx, function ($c) use (&$cchrCount, $startCchr, $endCchr) { + ++$cchrCount; + + return $startCchr.'\u{'.strtoupper(dechex(mb_ord($c[0]))).'}'.$endCchr; + }, $value); + } + if ($this->colors) { if ($cchrCount && "\033" === $value[0]) { $value = substr($value, \strlen($startCchr)); diff --git a/Dumper/HtmlDumper.php b/Dumper/HtmlDumper.php index c818c919..0cc7baab 100644 --- a/Dumper/HtmlDumper.php +++ b/Dumper/HtmlDumper.php @@ -862,7 +862,6 @@ protected function style(string $style, string $value, array $attr = []): string } elseif ('private' === $style) { $style .= sprintf(' title="Private property defined in class: `%s`"', esc($this->utf8Encode($attr['class']))); } - $map = static::$controlCharsMap; if (isset($attr['ellipsis'])) { $class = 'sf-dump-ellipsis'; @@ -881,6 +880,7 @@ protected function style(string $style, string $value, array $attr = []): string } } + $map = static::$controlCharsMap; $v = "".preg_replace_callback(static::$controlCharsRx, function ($c) use ($map) { $s = $b = '\u{'.strtoupper(dechex(mb_ord($c[0]))).'}'; + }, $v); + } + if (isset($attr['file']) && $href = $this->getSourceLink($attr['file'], $attr['line'] ?? 0)) { $attr['href'] = $href; } diff --git a/Tests/Dumper/CliDumperTest.php b/Tests/Dumper/CliDumperTest.php index b4780cfe..4993ee32 100644 --- a/Tests/Dumper/CliDumperTest.php +++ b/Tests/Dumper/CliDumperTest.php @@ -51,7 +51,7 @@ public function testGet() $this->assertStringMatchesFormat( << 1 0 => &1 null "const" => 1.1 @@ -66,6 +66,7 @@ public function testGet() é\\x01test\\t\\n ing """ + "bo\\u{FEFF}m" => "te\\u{FEFF}st" "[]" => [] "res" => stream resource {@{$res} %A wrapper_type: "plainfile" diff --git a/Tests/Dumper/HtmlDumperTest.php b/Tests/Dumper/HtmlDumperTest.php index 1fd98640..e48ed5e0 100644 --- a/Tests/Dumper/HtmlDumperTest.php +++ b/Tests/Dumper/HtmlDumperTest.php @@ -54,7 +54,7 @@ public function testGet() $this->assertStringMatchesFormat( <<array:24 [ +array:25 [ "number" => 1 0 => &1 null "const" => 1.1 @@ -69,6 +69,7 @@ public function testGet() é\\x01test\\t\\n ing """ + "bo "te[]" => [] "res" => stream resource @{$res} %A wrapper_type: "plainfile" diff --git a/Tests/Fixtures/dumb-var.php b/Tests/Fixtures/dumb-var.php index fc48012f..3896f310 100644 --- a/Tests/Fixtures/dumb-var.php +++ b/Tests/Fixtures/dumb-var.php @@ -1,5 +1,14 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace Symfony\Component\VarDumper\Tests\Fixture; if (!class_exists(\Symfony\Component\VarDumper\Tests\Fixture\DumbFoo::class)) { @@ -17,8 +26,8 @@ class DumbFoo $var = [ 'number' => 1, null, - 'const' => 1.1, true, false, NAN, INF, -INF, PHP_INT_MAX, - 'str' => "déjà\n", "\xE9\x01test\t\ning", + 'const' => 1.1, true, false, \NAN, \INF, -\INF, \PHP_INT_MAX, + 'str' => "déjà\n", "\xE9\x01test\t\ning", "bo\u{feff}m" => "te\u{feff}st", '[]' => [], 'res' => $g, 'obj' => $foo, From 54f93ba011820ff51bab14b1a98c2a59b549478d Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Thu, 9 Feb 2023 18:28:49 +0100 Subject: [PATCH 08/90] Use xxh128 instead of md5 --- Cloner/VarCloner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cloner/VarCloner.php b/Cloner/VarCloner.php index 4068c7c3..4f5c3471 100644 --- a/Cloner/VarCloner.php +++ b/Cloner/VarCloner.php @@ -41,7 +41,7 @@ protected function doClone(mixed $var): array $stub = null; // Stub capturing the main properties of an original item value // or null if the original value is used directly - $gid = self::$gid ??= md5(random_bytes(6)); // Unique string used to detect the special $GLOBALS variable + $gid = self::$gid ??= hash('xxh128', random_bytes(6)); // Unique string used to detect the special $GLOBALS variable $arrayStub = new Stub(); $arrayStub->type = Stub::TYPE_ARRAY; $fromObjCast = false; From 129d0c0440ebd9db956bcc5a9a4de40c3c26757b Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Mon, 13 Feb 2023 00:00:11 +0100 Subject: [PATCH 09/90] Add missing PHPdoc return types --- Caster/AmqpCaster.php | 15 ++++++++++++ Caster/DOMCaster.php | 45 +++++++++++++++++++++++++++++++++++ Caster/DateCaster.php | 12 ++++++++++ Caster/DoctrineCaster.php | 9 +++++++ Caster/ExceptionCaster.php | 21 ++++++++++++++++ Caster/FiberCaster.php | 3 +++ Caster/IntlCaster.php | 15 ++++++++++++ Caster/MemcachedCaster.php | 3 +++ Caster/PdoCaster.php | 6 +++++ Caster/PgSqlCaster.php | 9 +++++++ Caster/ProxyManagerCaster.php | 3 +++ Caster/RdKafkaCaster.php | 30 +++++++++++++++++++++++ Caster/RedisCaster.php | 9 +++++++ Caster/ReflectionCaster.php | 45 +++++++++++++++++++++++++++++++++++ Caster/ResourceCaster.php | 15 ++++++++++++ Caster/SplCaster.php | 30 +++++++++++++++++++++++ Caster/StubCaster.php | 12 ++++++++++ Caster/SymfonyCaster.php | 18 ++++++++++++++ Caster/XmlReaderCaster.php | 3 +++ Caster/XmlResourceCaster.php | 3 +++ Server/Connection.php | 3 +++ 21 files changed, 309 insertions(+) diff --git a/Caster/AmqpCaster.php b/Caster/AmqpCaster.php index dc3b6219..22026f46 100644 --- a/Caster/AmqpCaster.php +++ b/Caster/AmqpCaster.php @@ -46,6 +46,9 @@ class AmqpCaster \AMQP_EX_TYPE_HEADERS => 'AMQP_EX_TYPE_HEADERS', ]; + /** + * @return array + */ public static function castConnection(\AMQPConnection $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; @@ -79,6 +82,9 @@ public static function castConnection(\AMQPConnection $c, array $a, Stub $stub, return $a; } + /** + * @return array + */ public static function castChannel(\AMQPChannel $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; @@ -102,6 +108,9 @@ public static function castChannel(\AMQPChannel $c, array $a, Stub $stub, bool $ return $a; } + /** + * @return array + */ public static function castQueue(\AMQPQueue $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; @@ -125,6 +134,9 @@ public static function castQueue(\AMQPQueue $c, array $a, Stub $stub, bool $isNe return $a; } + /** + * @return array + */ public static function castExchange(\AMQPExchange $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; @@ -153,6 +165,9 @@ public static function castExchange(\AMQPExchange $c, array $a, Stub $stub, bool return $a; } + /** + * @return array + */ public static function castEnvelope(\AMQPEnvelope $c, array $a, Stub $stub, bool $isNested, int $filter = 0) { $prefix = Caster::PREFIX_VIRTUAL; diff --git a/Caster/DOMCaster.php b/Caster/DOMCaster.php index 8b770b8a..d2d3fc12 100644 --- a/Caster/DOMCaster.php +++ b/Caster/DOMCaster.php @@ -63,6 +63,9 @@ class DOMCaster \XML_NAMESPACE_DECL_NODE => 'XML_NAMESPACE_DECL_NODE', ]; + /** + * @return array + */ public static function castException(\DOMException $e, array $a, Stub $stub, bool $isNested) { $k = Caster::PREFIX_PROTECTED.'code'; @@ -73,6 +76,9 @@ public static function castException(\DOMException $e, array $a, Stub $stub, boo return $a; } + /** + * @return array + */ public static function castLength($dom, array $a, Stub $stub, bool $isNested) { $a += [ @@ -82,6 +88,9 @@ public static function castLength($dom, array $a, Stub $stub, bool $isNested) return $a; } + /** + * @return array + */ public static function castImplementation(\DOMImplementation $dom, array $a, Stub $stub, bool $isNested) { $a += [ @@ -92,6 +101,9 @@ public static function castImplementation(\DOMImplementation $dom, array $a, Stu return $a; } + /** + * @return array + */ public static function castNode(\DOMNode $dom, array $a, Stub $stub, bool $isNested) { $a += [ @@ -116,6 +128,9 @@ public static function castNode(\DOMNode $dom, array $a, Stub $stub, bool $isNes return $a; } + /** + * @return array + */ public static function castNameSpaceNode(\DOMNameSpaceNode $dom, array $a, Stub $stub, bool $isNested) { $a += [ @@ -132,6 +147,9 @@ public static function castNameSpaceNode(\DOMNameSpaceNode $dom, array $a, Stub return $a; } + /** + * @return array + */ public static function castDocument(\DOMDocument $dom, array $a, Stub $stub, bool $isNested, int $filter = 0) { $a += [ @@ -166,6 +184,9 @@ public static function castDocument(\DOMDocument $dom, array $a, Stub $stub, boo return $a; } + /** + * @return array + */ public static function castCharacterData(\DOMCharacterData $dom, array $a, Stub $stub, bool $isNested) { $a += [ @@ -176,6 +197,9 @@ public static function castCharacterData(\DOMCharacterData $dom, array $a, Stub return $a; } + /** + * @return array + */ public static function castAttr(\DOMAttr $dom, array $a, Stub $stub, bool $isNested) { $a += [ @@ -189,6 +213,9 @@ public static function castAttr(\DOMAttr $dom, array $a, Stub $stub, bool $isNes return $a; } + /** + * @return array + */ public static function castElement(\DOMElement $dom, array $a, Stub $stub, bool $isNested) { $a += [ @@ -199,6 +226,9 @@ public static function castElement(\DOMElement $dom, array $a, Stub $stub, bool return $a; } + /** + * @return array + */ public static function castText(\DOMText $dom, array $a, Stub $stub, bool $isNested) { $a += [ @@ -208,6 +238,9 @@ public static function castText(\DOMText $dom, array $a, Stub $stub, bool $isNes return $a; } + /** + * @return array + */ public static function castDocumentType(\DOMDocumentType $dom, array $a, Stub $stub, bool $isNested) { $a += [ @@ -222,6 +255,9 @@ public static function castDocumentType(\DOMDocumentType $dom, array $a, Stub $s return $a; } + /** + * @return array + */ public static function castNotation(\DOMNotation $dom, array $a, Stub $stub, bool $isNested) { $a += [ @@ -232,6 +268,9 @@ public static function castNotation(\DOMNotation $dom, array $a, Stub $stub, boo return $a; } + /** + * @return array + */ public static function castEntity(\DOMEntity $dom, array $a, Stub $stub, bool $isNested) { $a += [ @@ -246,6 +285,9 @@ public static function castEntity(\DOMEntity $dom, array $a, Stub $stub, bool $i return $a; } + /** + * @return array + */ public static function castProcessingInstruction(\DOMProcessingInstruction $dom, array $a, Stub $stub, bool $isNested) { $a += [ @@ -256,6 +298,9 @@ public static function castProcessingInstruction(\DOMProcessingInstruction $dom, return $a; } + /** + * @return array + */ public static function castXPath(\DOMXPath $dom, array $a, Stub $stub, bool $isNested) { $a += [ diff --git a/Caster/DateCaster.php b/Caster/DateCaster.php index 07e8c5ea..1394a781 100644 --- a/Caster/DateCaster.php +++ b/Caster/DateCaster.php @@ -24,6 +24,9 @@ class DateCaster { private const PERIOD_LIMIT = 3; + /** + * @return array + */ public static function castDateTime(\DateTimeInterface $d, array $a, Stub $stub, bool $isNested, int $filter) { $prefix = Caster::PREFIX_VIRTUAL; @@ -47,6 +50,9 @@ public static function castDateTime(\DateTimeInterface $d, array $a, Stub $stub, return $a; } + /** + * @return array + */ public static function castInterval(\DateInterval $interval, array $a, Stub $stub, bool $isNested, int $filter) { $now = new \DateTimeImmutable('@0', new \DateTimeZone('UTC')); @@ -76,6 +82,9 @@ private static function formatInterval(\DateInterval $i): string return $i->format(rtrim($format)); } + /** + * @return array + */ public static function castTimeZone(\DateTimeZone $timeZone, array $a, Stub $stub, bool $isNested, int $filter) { $location = $timeZone->getLocation(); @@ -87,6 +96,9 @@ public static function castTimeZone(\DateTimeZone $timeZone, array $a, Stub $stu return $filter & Caster::EXCLUDE_VERBOSE ? $z : $z + $a; } + /** + * @return array + */ public static function castPeriod(\DatePeriod $p, array $a, Stub $stub, bool $isNested, int $filter) { $dates = []; diff --git a/Caster/DoctrineCaster.php b/Caster/DoctrineCaster.php index 129b2cb4..3120c3d9 100644 --- a/Caster/DoctrineCaster.php +++ b/Caster/DoctrineCaster.php @@ -25,6 +25,9 @@ */ class DoctrineCaster { + /** + * @return array + */ public static function castCommonProxy(CommonProxy $proxy, array $a, Stub $stub, bool $isNested) { foreach (['__cloner__', '__initializer__'] as $k) { @@ -37,6 +40,9 @@ public static function castCommonProxy(CommonProxy $proxy, array $a, Stub $stub, return $a; } + /** + * @return array + */ public static function castOrmProxy(OrmProxy $proxy, array $a, Stub $stub, bool $isNested) { foreach (['_entityPersister', '_identifier'] as $k) { @@ -49,6 +55,9 @@ public static function castOrmProxy(OrmProxy $proxy, array $a, Stub $stub, bool return $a; } + /** + * @return array + */ public static function castPersistentCollection(PersistentCollection $coll, array $a, Stub $stub, bool $isNested) { foreach (['snapshot', 'association', 'typeClass'] as $k) { diff --git a/Caster/ExceptionCaster.php b/Caster/ExceptionCaster.php index 80a91ead..c58e74a5 100644 --- a/Caster/ExceptionCaster.php +++ b/Caster/ExceptionCaster.php @@ -46,16 +46,25 @@ class ExceptionCaster private static array $framesCache = []; + /** + * @return array + */ public static function castError(\Error $e, array $a, Stub $stub, bool $isNested, int $filter = 0) { return self::filterExceptionArray($stub->class, $a, "\0Error\0", $filter); } + /** + * @return array + */ public static function castException(\Exception $e, array $a, Stub $stub, bool $isNested, int $filter = 0) { return self::filterExceptionArray($stub->class, $a, "\0Exception\0", $filter); } + /** + * @return array + */ public static function castErrorException(\ErrorException $e, array $a, Stub $stub, bool $isNested) { if (isset($a[$s = Caster::PREFIX_PROTECTED.'severity'], self::$errorTypes[$a[$s]])) { @@ -65,6 +74,9 @@ public static function castErrorException(\ErrorException $e, array $a, Stub $st return $a; } + /** + * @return array + */ public static function castThrowingCasterException(ThrowingCasterException $e, array $a, Stub $stub, bool $isNested) { $trace = Caster::PREFIX_VIRTUAL.'trace'; @@ -83,6 +95,9 @@ public static function castThrowingCasterException(ThrowingCasterException $e, a return $a; } + /** + * @return array + */ public static function castSilencedErrorContext(SilencedErrorContext $e, array $a, Stub $stub, bool $isNested) { $sPrefix = "\0".SilencedErrorContext::class."\0"; @@ -110,6 +125,9 @@ public static function castSilencedErrorContext(SilencedErrorContext $e, array $ return $a; } + /** + * @return array + */ public static function castTraceStub(TraceStub $trace, array $a, Stub $stub, bool $isNested) { if (!$isNested) { @@ -184,6 +202,9 @@ public static function castTraceStub(TraceStub $trace, array $a, Stub $stub, boo return $a; } + /** + * @return array + */ public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, bool $isNested) { if (!$isNested) { diff --git a/Caster/FiberCaster.php b/Caster/FiberCaster.php index c74a9e59..b797dbd6 100644 --- a/Caster/FiberCaster.php +++ b/Caster/FiberCaster.php @@ -20,6 +20,9 @@ */ final class FiberCaster { + /** + * @return array + */ public static function castFiber(\Fiber $fiber, array $a, Stub $stub, bool $isNested, int $filter = 0) { $prefix = Caster::PREFIX_VIRTUAL; diff --git a/Caster/IntlCaster.php b/Caster/IntlCaster.php index 1ed91d4d..a4590f4b 100644 --- a/Caster/IntlCaster.php +++ b/Caster/IntlCaster.php @@ -21,6 +21,9 @@ */ class IntlCaster { + /** + * @return array + */ public static function castMessageFormatter(\MessageFormatter $c, array $a, Stub $stub, bool $isNested) { $a += [ @@ -31,6 +34,9 @@ public static function castMessageFormatter(\MessageFormatter $c, array $a, Stub return self::castError($c, $a); } + /** + * @return array + */ public static function castNumberFormatter(\NumberFormatter $c, array $a, Stub $stub, bool $isNested, int $filter = 0) { $a += [ @@ -108,6 +114,9 @@ public static function castNumberFormatter(\NumberFormatter $c, array $a, Stub $ return self::castError($c, $a); } + /** + * @return array + */ public static function castIntlTimeZone(\IntlTimeZone $c, array $a, Stub $stub, bool $isNested) { $a += [ @@ -125,6 +134,9 @@ public static function castIntlTimeZone(\IntlTimeZone $c, array $a, Stub $stub, return self::castError($c, $a); } + /** + * @return array + */ public static function castIntlCalendar(\IntlCalendar $c, array $a, Stub $stub, bool $isNested, int $filter = 0) { $a += [ @@ -142,6 +154,9 @@ public static function castIntlCalendar(\IntlCalendar $c, array $a, Stub $stub, return self::castError($c, $a); } + /** + * @return array + */ public static function castIntlDateFormatter(\IntlDateFormatter $c, array $a, Stub $stub, bool $isNested, int $filter = 0) { $a += [ diff --git a/Caster/MemcachedCaster.php b/Caster/MemcachedCaster.php index bc1fd63f..2f161e8c 100644 --- a/Caster/MemcachedCaster.php +++ b/Caster/MemcachedCaster.php @@ -23,6 +23,9 @@ class MemcachedCaster private static array $optionConstants; private static array $defaultOptions; + /** + * @return array + */ public static function castMemcached(\Memcached $c, array $a, Stub $stub, bool $isNested) { $a += [ diff --git a/Caster/PdoCaster.php b/Caster/PdoCaster.php index 0372a630..d68eae21 100644 --- a/Caster/PdoCaster.php +++ b/Caster/PdoCaster.php @@ -59,6 +59,9 @@ class PdoCaster ], ]; + /** + * @return array + */ public static function castPdo(\PDO $c, array $a, Stub $stub, bool $isNested) { $attr = []; @@ -108,6 +111,9 @@ public static function castPdo(\PDO $c, array $a, Stub $stub, bool $isNested) return $a; } + /** + * @return array + */ public static function castPdoStatement(\PDOStatement $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; diff --git a/Caster/PgSqlCaster.php b/Caster/PgSqlCaster.php index d8e5b525..0d8b3d91 100644 --- a/Caster/PgSqlCaster.php +++ b/Caster/PgSqlCaster.php @@ -69,6 +69,9 @@ class PgSqlCaster 'function' => \PGSQL_DIAG_SOURCE_FUNCTION, ]; + /** + * @return array + */ public static function castLargeObject($lo, array $a, Stub $stub, bool $isNested) { $a['seek position'] = pg_lo_tell($lo); @@ -76,6 +79,9 @@ public static function castLargeObject($lo, array $a, Stub $stub, bool $isNested return $a; } + /** + * @return array + */ public static function castLink($link, array $a, Stub $stub, bool $isNested) { $a['status'] = pg_connection_status($link); @@ -108,6 +114,9 @@ public static function castLink($link, array $a, Stub $stub, bool $isNested) return $a; } + /** + * @return array + */ public static function castResult($result, array $a, Stub $stub, bool $isNested) { $a['num rows'] = pg_num_rows($result); diff --git a/Caster/ProxyManagerCaster.php b/Caster/ProxyManagerCaster.php index e7120191..eb6c88db 100644 --- a/Caster/ProxyManagerCaster.php +++ b/Caster/ProxyManagerCaster.php @@ -21,6 +21,9 @@ */ class ProxyManagerCaster { + /** + * @return array + */ public static function castProxy(ProxyInterface $c, array $a, Stub $stub, bool $isNested) { if ($parent = get_parent_class($c)) { diff --git a/Caster/RdKafkaCaster.php b/Caster/RdKafkaCaster.php index 82b8c8af..9e91592b 100644 --- a/Caster/RdKafkaCaster.php +++ b/Caster/RdKafkaCaster.php @@ -51,6 +51,9 @@ public static function castKafkaConsumer(KafkaConsumer $c, array $a, Stub $stub, return $a; } + /** + * @return array + */ public static function castTopic(Topic $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; @@ -62,6 +65,9 @@ public static function castTopic(Topic $c, array $a, Stub $stub, bool $isNested) return $a; } + /** + * @return array + */ public static function castTopicPartition(TopicPartition $c, array $a) { $prefix = Caster::PREFIX_VIRTUAL; @@ -75,6 +81,9 @@ public static function castTopicPartition(TopicPartition $c, array $a) return $a; } + /** + * @return array + */ public static function castMessage(Message $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; @@ -86,6 +95,9 @@ public static function castMessage(Message $c, array $a, Stub $stub, bool $isNes return $a; } + /** + * @return array + */ public static function castConf(Conf $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; @@ -97,6 +109,9 @@ public static function castConf(Conf $c, array $a, Stub $stub, bool $isNested) return $a; } + /** + * @return array + */ public static function castTopicConf(TopicConf $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; @@ -121,6 +136,9 @@ public static function castRdKafka(\RdKafka $c, array $a, Stub $stub, bool $isNe return $a; } + /** + * @return array + */ public static function castCollectionMetadata(CollectionMetadata $c, array $a, Stub $stub, bool $isNested) { $a += iterator_to_array($c); @@ -128,6 +146,9 @@ public static function castCollectionMetadata(CollectionMetadata $c, array $a, S return $a; } + /** + * @return array + */ public static function castTopicMetadata(TopicMetadata $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; @@ -140,6 +161,9 @@ public static function castTopicMetadata(TopicMetadata $c, array $a, Stub $stub, return $a; } + /** + * @return array + */ public static function castPartitionMetadata(PartitionMetadata $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; @@ -153,6 +177,9 @@ public static function castPartitionMetadata(PartitionMetadata $c, array $a, Stu return $a; } + /** + * @return array + */ public static function castBrokerMetadata(BrokerMetadata $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; @@ -166,6 +193,9 @@ public static function castBrokerMetadata(BrokerMetadata $c, array $a, Stub $stu return $a; } + /** + * @return array + */ private static function extractMetadata(KafkaConsumer|\RdKafka $c) { $prefix = Caster::PREFIX_VIRTUAL; diff --git a/Caster/RedisCaster.php b/Caster/RedisCaster.php index f88c72a4..6ff04675 100644 --- a/Caster/RedisCaster.php +++ b/Caster/RedisCaster.php @@ -47,6 +47,9 @@ class RedisCaster \RedisCluster::FAILOVER_DISTRIBUTE_SLAVES => 'DISTRIBUTE_SLAVES', ]; + /** + * @return array + */ public static function castRedis(\Redis|Relay $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; @@ -73,6 +76,9 @@ public static function castRedis(\Redis|Relay $c, array $a, Stub $stub, bool $is ]; } + /** + * @return array + */ public static function castRedisArray(\RedisArray $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; @@ -85,6 +91,9 @@ public static function castRedisArray(\RedisArray $c, array $a, Stub $stub, bool ]; } + /** + * @return array + */ public static function castRedisCluster(\RedisCluster $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; diff --git a/Caster/ReflectionCaster.php b/Caster/ReflectionCaster.php index f6c8c741..0569278c 100644 --- a/Caster/ReflectionCaster.php +++ b/Caster/ReflectionCaster.php @@ -35,6 +35,9 @@ class ReflectionCaster 'isVariadic' => 'isVariadic', ]; + /** + * @return array + */ public static function castClosure(\Closure $c, array $a, Stub $stub, bool $isNested, int $filter = 0) { $prefix = Caster::PREFIX_VIRTUAL; @@ -71,6 +74,9 @@ public static function castClosure(\Closure $c, array $a, Stub $stub, bool $isNe return $a; } + /** + * @return array + */ public static function unsetClosureFileInfo(\Closure $c, array $a) { unset($a[Caster::PREFIX_VIRTUAL.'file'], $a[Caster::PREFIX_VIRTUAL.'line']); @@ -92,6 +98,9 @@ public static function castGenerator(\Generator $c, array $a, Stub $stub, bool $ return self::castReflectionGenerator($reflectionGenerator, $a, $stub, $isNested); } + /** + * @return array + */ public static function castType(\ReflectionType $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; @@ -114,6 +123,9 @@ public static function castType(\ReflectionType $c, array $a, Stub $stub, bool $ return $a; } + /** + * @return array + */ public static function castAttribute(\ReflectionAttribute $c, array $a, Stub $stub, bool $isNested) { self::addMap($a, $c, [ @@ -124,6 +136,9 @@ public static function castAttribute(\ReflectionAttribute $c, array $a, Stub $st return $a; } + /** + * @return array + */ public static function castReflectionGenerator(\ReflectionGenerator $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; @@ -159,6 +174,9 @@ public static function castReflectionGenerator(\ReflectionGenerator $c, array $a return $a; } + /** + * @return array + */ public static function castClass(\ReflectionClass $c, array $a, Stub $stub, bool $isNested, int $filter = 0) { $prefix = Caster::PREFIX_VIRTUAL; @@ -190,6 +208,9 @@ public static function castClass(\ReflectionClass $c, array $a, Stub $stub, bool return $a; } + /** + * @return array + */ public static function castFunctionAbstract(\ReflectionFunctionAbstract $c, array $a, Stub $stub, bool $isNested, int $filter = 0) { $prefix = Caster::PREFIX_VIRTUAL; @@ -248,6 +269,9 @@ public static function castFunctionAbstract(\ReflectionFunctionAbstract $c, arra return $a; } + /** + * @return array + */ public static function castClassConstant(\ReflectionClassConstant $c, array $a, Stub $stub, bool $isNested) { $a[Caster::PREFIX_VIRTUAL.'modifiers'] = implode(' ', \Reflection::getModifierNames($c->getModifiers())); @@ -258,6 +282,9 @@ public static function castClassConstant(\ReflectionClassConstant $c, array $a, return $a; } + /** + * @return array + */ public static function castMethod(\ReflectionMethod $c, array $a, Stub $stub, bool $isNested) { $a[Caster::PREFIX_VIRTUAL.'modifiers'] = implode(' ', \Reflection::getModifierNames($c->getModifiers())); @@ -265,6 +292,9 @@ public static function castMethod(\ReflectionMethod $c, array $a, Stub $stub, bo return $a; } + /** + * @return array + */ public static function castParameter(\ReflectionParameter $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; @@ -305,6 +335,9 @@ public static function castParameter(\ReflectionParameter $c, array $a, Stub $st return $a; } + /** + * @return array + */ public static function castProperty(\ReflectionProperty $c, array $a, Stub $stub, bool $isNested) { $a[Caster::PREFIX_VIRTUAL.'modifiers'] = implode(' ', \Reflection::getModifierNames($c->getModifiers())); @@ -315,6 +348,9 @@ public static function castProperty(\ReflectionProperty $c, array $a, Stub $stub return $a; } + /** + * @return array + */ public static function castReference(\ReflectionReference $c, array $a, Stub $stub, bool $isNested) { $a[Caster::PREFIX_VIRTUAL.'id'] = $c->getId(); @@ -322,6 +358,9 @@ public static function castReference(\ReflectionReference $c, array $a, Stub $st return $a; } + /** + * @return array + */ public static function castExtension(\ReflectionExtension $c, array $a, Stub $stub, bool $isNested) { self::addMap($a, $c, [ @@ -338,6 +377,9 @@ public static function castExtension(\ReflectionExtension $c, array $a, Stub $st return $a; } + /** + * @return array + */ public static function castZendExtension(\ReflectionZendExtension $c, array $a, Stub $stub, bool $isNested) { self::addMap($a, $c, [ @@ -350,6 +392,9 @@ public static function castZendExtension(\ReflectionZendExtension $c, array $a, return $a; } + /** + * @return string + */ public static function getSignature(array $a) { $prefix = Caster::PREFIX_VIRTUAL; diff --git a/Caster/ResourceCaster.php b/Caster/ResourceCaster.php index 6db234e8..f8c53446 100644 --- a/Caster/ResourceCaster.php +++ b/Caster/ResourceCaster.php @@ -27,6 +27,9 @@ public static function castCurl(\CurlHandle $h, array $a, Stub $stub, bool $isNe return curl_getinfo($h); } + /** + * @return array + */ public static function castDba($dba, array $a, Stub $stub, bool $isNested) { $list = dba_list(); @@ -35,6 +38,9 @@ public static function castDba($dba, array $a, Stub $stub, bool $isNested) return $a; } + /** + * @return array + */ public static function castProcess($process, array $a, Stub $stub, bool $isNested) { return proc_get_status($process); @@ -50,11 +56,17 @@ public static function castStream($stream, array $a, Stub $stub, bool $isNested) return $a; } + /** + * @return array + */ public static function castStreamContext($stream, array $a, Stub $stub, bool $isNested) { return @stream_context_get_params($stream) ?: $a; } + /** + * @return array + */ public static function castGd($gd, array $a, Stub $stub, bool $isNested) { $a['size'] = imagesx($gd).'x'.imagesy($gd); @@ -63,6 +75,9 @@ public static function castGd($gd, array $a, Stub $stub, bool $isNested) return $a; } + /** + * @return array + */ public static function castOpensslX509($h, array $a, Stub $stub, bool $isNested) { $stub->cut = -1; diff --git a/Caster/SplCaster.php b/Caster/SplCaster.php index 72ac5dce..ea86cb49 100644 --- a/Caster/SplCaster.php +++ b/Caster/SplCaster.php @@ -29,16 +29,25 @@ class SplCaster \SplFileObject::READ_CSV => 'READ_CSV', ]; + /** + * @return array + */ public static function castArrayObject(\ArrayObject $c, array $a, Stub $stub, bool $isNested) { return self::castSplArray($c, $a, $stub, $isNested); } + /** + * @return array + */ public static function castArrayIterator(\ArrayIterator $c, array $a, Stub $stub, bool $isNested) { return self::castSplArray($c, $a, $stub, $isNested); } + /** + * @return array + */ public static function castHeap(\Iterator $c, array $a, Stub $stub, bool $isNested) { $a += [ @@ -48,6 +57,9 @@ public static function castHeap(\Iterator $c, array $a, Stub $stub, bool $isNest return $a; } + /** + * @return array + */ public static function castDoublyLinkedList(\SplDoublyLinkedList $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; @@ -63,6 +75,9 @@ public static function castDoublyLinkedList(\SplDoublyLinkedList $c, array $a, S return $a; } + /** + * @return array + */ public static function castFileInfo(\SplFileInfo $c, array $a, Stub $stub, bool $isNested) { static $map = [ @@ -139,6 +154,9 @@ public static function castFileInfo(\SplFileInfo $c, array $a, Stub $stub, bool return $a; } + /** + * @return array + */ public static function castFileObject(\SplFileObject $c, array $a, Stub $stub, bool $isNested) { static $map = [ @@ -176,6 +194,9 @@ public static function castFileObject(\SplFileObject $c, array $a, Stub $stub, b return $a; } + /** + * @return array + */ public static function castObjectStorage(\SplObjectStorage $c, array $a, Stub $stub, bool $isNested) { $storage = []; @@ -197,6 +218,9 @@ public static function castObjectStorage(\SplObjectStorage $c, array $a, Stub $s return $a; } + /** + * @return array + */ public static function castOuterIterator(\OuterIterator $c, array $a, Stub $stub, bool $isNested) { $a[Caster::PREFIX_VIRTUAL.'innerIterator'] = $c->getInnerIterator(); @@ -204,6 +228,9 @@ public static function castOuterIterator(\OuterIterator $c, array $a, Stub $stub return $a; } + /** + * @return array + */ public static function castWeakReference(\WeakReference $c, array $a, Stub $stub, bool $isNested) { $a[Caster::PREFIX_VIRTUAL.'object'] = $c->get(); @@ -211,6 +238,9 @@ public static function castWeakReference(\WeakReference $c, array $a, Stub $stub return $a; } + /** + * @return array + */ public static function castWeakMap(\WeakMap $c, array $a, Stub $stub, bool $isNested) { $map = []; diff --git a/Caster/StubCaster.php b/Caster/StubCaster.php index 9318ad1f..3fef0569 100644 --- a/Caster/StubCaster.php +++ b/Caster/StubCaster.php @@ -22,6 +22,9 @@ */ class StubCaster { + /** + * @return array + */ public static function castStub(Stub $c, array $a, Stub $stub, bool $isNested) { if ($isNested) { @@ -48,6 +51,9 @@ public static function castCutArray(CutArrayStub $c, array $a, Stub $stub, bool return $isNested ? $c->preservedSubset : $a; } + /** + * @return array + */ public static function cutInternals($obj, array $a, Stub $stub, bool $isNested) { if ($isNested) { @@ -59,6 +65,9 @@ public static function cutInternals($obj, array $a, Stub $stub, bool $isNested) return $a; } + /** + * @return array + */ public static function castEnum(EnumStub $c, array $a, Stub $stub, bool $isNested) { if ($isNested) { @@ -82,6 +91,9 @@ public static function castEnum(EnumStub $c, array $a, Stub $stub, bool $isNeste return $a; } + /** + * @return array + */ public static function castScalar(ScalarStub $scalarStub, array $a, Stub $stub) { $stub->type = Stub::TYPE_SCALAR; diff --git a/Caster/SymfonyCaster.php b/Caster/SymfonyCaster.php index 3b13666c..ebc00f90 100644 --- a/Caster/SymfonyCaster.php +++ b/Caster/SymfonyCaster.php @@ -31,6 +31,9 @@ class SymfonyCaster 'format' => 'getRequestFormat', ]; + /** + * @return array + */ public static function castRequest(Request $request, array $a, Stub $stub, bool $isNested) { $clone = null; @@ -46,6 +49,9 @@ public static function castRequest(Request $request, array $a, Stub $stub, bool return $a; } + /** + * @return array + */ public static function castHttpClient($client, array $a, Stub $stub, bool $isNested) { $multiKey = sprintf("\0%s\0multi", $client::class); @@ -56,6 +62,9 @@ public static function castHttpClient($client, array $a, Stub $stub, bool $isNes return $a; } + /** + * @return array + */ public static function castHttpClientResponse($response, array $a, Stub $stub, bool $isNested) { $stub->cut += \count($a); @@ -68,6 +77,9 @@ public static function castHttpClientResponse($response, array $a, Stub $stub, b return $a; } + /** + * @return array + */ public static function castLazyObjectState($state, array $a, Stub $stub, bool $isNested) { if (!$isNested) { @@ -93,6 +105,9 @@ public static function castLazyObjectState($state, array $a, Stub $stub, bool $i return $a; } + /** + * @return array + */ public static function castUuid(Uuid $uuid, array $a, Stub $stub, bool $isNested) { $a[Caster::PREFIX_VIRTUAL.'toBase58'] = $uuid->toBase58(); @@ -106,6 +121,9 @@ public static function castUuid(Uuid $uuid, array $a, Stub $stub, bool $isNested return $a; } + /** + * @return array + */ public static function castUlid(Ulid $ulid, array $a, Stub $stub, bool $isNested) { $a[Caster::PREFIX_VIRTUAL.'toBase58'] = $ulid->toBase58(); diff --git a/Caster/XmlReaderCaster.php b/Caster/XmlReaderCaster.php index 506746b4..d802bbf2 100644 --- a/Caster/XmlReaderCaster.php +++ b/Caster/XmlReaderCaster.php @@ -43,6 +43,9 @@ class XmlReaderCaster \XMLReader::XML_DECLARATION => 'XML_DECLARATION', ]; + /** + * @return array + */ public static function castXmlReader(\XMLReader $reader, array $a, Stub $stub, bool $isNested) { try { diff --git a/Caster/XmlResourceCaster.php b/Caster/XmlResourceCaster.php index ba55fced..0cf42584 100644 --- a/Caster/XmlResourceCaster.php +++ b/Caster/XmlResourceCaster.php @@ -47,6 +47,9 @@ class XmlResourceCaster \XML_ERROR_EXTERNAL_ENTITY_HANDLING => 'XML_ERROR_EXTERNAL_ENTITY_HANDLING', ]; + /** + * @return array + */ public static function castXml($h, array $a, Stub $stub, bool $isNested) { $a['current_byte_index'] = xml_get_current_byte_index($h); diff --git a/Server/Connection.php b/Server/Connection.php index 97b5b94f..23fa456b 100644 --- a/Server/Connection.php +++ b/Server/Connection.php @@ -87,6 +87,9 @@ private static function nullErrorHandler(int $t, string $m) // no-op } + /** + * @psalm-return false|resource + */ private function createSocket() { set_error_handler([self::class, 'nullErrorHandler']); From 20963cfbd7c5d517a0f346c56a8029973b3e77bb Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Mon, 13 Feb 2023 00:00:27 +0100 Subject: [PATCH 10/90] Add PHP types to private methods and functions --- Dumper/HtmlDumper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dumper/HtmlDumper.php b/Dumper/HtmlDumper.php index 0cc7baab..91539daa 100644 --- a/Dumper/HtmlDumper.php +++ b/Dumper/HtmlDumper.php @@ -962,7 +962,7 @@ private function getSourceLink(string $file, int $line) } } -function esc(string $str) +function esc(string $str): string { return htmlspecialchars($str, \ENT_QUOTES, 'UTF-8'); } From bfeaa203d77f1a808fc80f0c3de1e65523ceb0a7 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sun, 12 Feb 2023 23:57:18 +0100 Subject: [PATCH 11/90] Add void return types --- Caster/RdKafkaCaster.php | 6 ++++++ Caster/ReflectionCaster.php | 6 +++--- Caster/ResourceCaster.php | 2 +- Cloner/AbstractCloner.php | 8 ++++++++ Cloner/Data.php | 4 +++- Command/ServerDumpCommand.php | 2 +- Dumper/AbstractDumper.php | 4 ++++ Dumper/CliDumper.php | 30 ++++++++++++++++++++++++++++++ Dumper/ContextualizedDumper.php | 3 +++ Dumper/ServerDumper.php | 3 +++ Server/Connection.php | 9 ++------- 11 files changed, 64 insertions(+), 13 deletions(-) diff --git a/Caster/RdKafkaCaster.php b/Caster/RdKafkaCaster.php index 9e91592b..fcaa1b76 100644 --- a/Caster/RdKafkaCaster.php +++ b/Caster/RdKafkaCaster.php @@ -31,6 +31,9 @@ */ class RdKafkaCaster { + /** + * @return array + */ public static function castKafkaConsumer(KafkaConsumer $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; @@ -123,6 +126,9 @@ public static function castTopicConf(TopicConf $c, array $a, Stub $stub, bool $i return $a; } + /** + * @return array + */ public static function castRdKafka(\RdKafka $c, array $a, Stub $stub, bool $isNested) { $prefix = Caster::PREFIX_VIRTUAL; diff --git a/Caster/ReflectionCaster.php b/Caster/ReflectionCaster.php index 0569278c..591751fc 100644 --- a/Caster/ReflectionCaster.php +++ b/Caster/ReflectionCaster.php @@ -84,7 +84,7 @@ public static function unsetClosureFileInfo(\Closure $c, array $a) return $a; } - public static function castGenerator(\Generator $c, array $a, Stub $stub, bool $isNested) + public static function castGenerator(\Generator $c, array $a, Stub $stub, bool $isNested): array { // Cannot create ReflectionGenerator based on a terminated Generator try { @@ -447,7 +447,7 @@ public static function getSignature(array $a) return $signature; } - private static function addExtra(array &$a, \Reflector $c) + private static function addExtra(array &$a, \Reflector $c): void { $x = isset($a[Caster::PREFIX_VIRTUAL.'extra']) ? $a[Caster::PREFIX_VIRTUAL.'extra']->value : []; @@ -463,7 +463,7 @@ private static function addExtra(array &$a, \Reflector $c) } } - private static function addMap(array &$a, object $c, array $map, string $prefix = Caster::PREFIX_VIRTUAL) + private static function addMap(array &$a, object $c, array $map, string $prefix = Caster::PREFIX_VIRTUAL): void { foreach ($map as $k => $m) { if ('isDisabled' === $k) { diff --git a/Caster/ResourceCaster.php b/Caster/ResourceCaster.php index f8c53446..f3bbf3be 100644 --- a/Caster/ResourceCaster.php +++ b/Caster/ResourceCaster.php @@ -46,7 +46,7 @@ public static function castProcess($process, array $a, Stub $stub, bool $isNeste return proc_get_status($process); } - public static function castStream($stream, array $a, Stub $stub, bool $isNested) + public static function castStream($stream, array $a, Stub $stub, bool $isNested): array { $a = stream_get_meta_data($stream) + static::castStreamContext($stream, $a, $stub, $isNested); if ($a['uri'] ?? false) { diff --git a/Cloner/AbstractCloner.php b/Cloner/AbstractCloner.php index 599c59ec..9df2b79f 100644 --- a/Cloner/AbstractCloner.php +++ b/Cloner/AbstractCloner.php @@ -232,6 +232,8 @@ public function __construct(array $casters = null) * see e.g. static::$defaultCasters. * * @param callable[] $casters A map of casters + * + * @return void */ public function addCasters(array $casters) { @@ -242,6 +244,8 @@ public function addCasters(array $casters) /** * Sets the maximum number of items to clone past the minimum depth in nested structures. + * + * @return void */ public function setMaxItems(int $maxItems) { @@ -250,6 +254,8 @@ public function setMaxItems(int $maxItems) /** * Sets the maximum cloned length for strings. + * + * @return void */ public function setMaxString(int $maxString) { @@ -259,6 +265,8 @@ public function setMaxString(int $maxString) /** * Sets the minimum tree depth where we are guaranteed to clone all the items. After this * depth is reached, only setMaxItems items will be cloned. + * + * @return void */ public function setMinDepth(int $minDepth) { diff --git a/Cloner/Data.php b/Cloner/Data.php index d87d5690..056b3dfb 100644 --- a/Cloner/Data.php +++ b/Cloner/Data.php @@ -262,6 +262,8 @@ public function seek(string|int $key): ?static /** * Dumps data with a DumperInterface dumper. + * + * @return void */ public function dump(DumperInterface $dumper) { @@ -286,7 +288,7 @@ public function dump(DumperInterface $dumper) * * @param mixed $item A Stub object or the original value being dumped */ - private function dumpItem(DumperInterface $dumper, Cursor $cursor, array &$refs, mixed $item) + private function dumpItem(DumperInterface $dumper, Cursor $cursor, array &$refs, mixed $item): void { $cursor->refIndex = 0; $cursor->softRefTo = $cursor->softRefHandle = $cursor->softRefCount = 0; diff --git a/Command/ServerDumpCommand.php b/Command/ServerDumpCommand.php index 1b06e694..b64a884b 100644 --- a/Command/ServerDumpCommand.php +++ b/Command/ServerDumpCommand.php @@ -54,7 +54,7 @@ public function __construct(DumpServer $server, array $descriptors = []) parent::__construct(); } - protected function configure() + protected function configure(): void { $this ->addOption('format', null, InputOption::VALUE_REQUIRED, sprintf('The output format (%s)', implode(', ', $this->getAvailableFormats())), 'cli') diff --git a/Dumper/AbstractDumper.php b/Dumper/AbstractDumper.php index 2740b879..053a9097 100644 --- a/Dumper/AbstractDumper.php +++ b/Dumper/AbstractDumper.php @@ -155,6 +155,8 @@ public function dump(Data $data, $output = null): ?string * * @param int $depth The recursive depth in the dumped structure for the line being dumped, * or -1 to signal the end-of-dump to the line dumper callable + * + * @return void */ protected function dumpLine(int $depth) { @@ -164,6 +166,8 @@ protected function dumpLine(int $depth) /** * Generic line dumper callback. + * + * @return void */ protected function echoLine(string $line, int $depth, string $indentPad) { diff --git a/Dumper/CliDumper.php b/Dumper/CliDumper.php index 7d6810e4..f5780a87 100644 --- a/Dumper/CliDumper.php +++ b/Dumper/CliDumper.php @@ -86,6 +86,8 @@ public function __construct($output = null, string $charset = null, int $flags = /** * Enables/disables colored output. + * + * @return void */ public function setColors(bool $colors) { @@ -94,6 +96,8 @@ public function setColors(bool $colors) /** * Sets the maximum number of characters per line for dumped strings. + * + * @return void */ public function setMaxStringWidth(int $maxStringWidth) { @@ -104,6 +108,8 @@ public function setMaxStringWidth(int $maxStringWidth) * Configures styles. * * @param array $styles A map of style names to style definitions + * + * @return void */ public function setStyles(array $styles) { @@ -114,12 +120,17 @@ public function setStyles(array $styles) * Configures display options. * * @param array $displayOptions A map of display options to customize the behavior + * + * @return void */ public function setDisplayOptions(array $displayOptions) { $this->displayOptions = $displayOptions + $this->displayOptions; } + /** + * @return void + */ public function dumpScalar(Cursor $cursor, string $type, string|int|float|bool|null $value) { $this->dumpKey($cursor); @@ -175,6 +186,9 @@ public function dumpScalar(Cursor $cursor, string $type, string|int|float|bool|n $this->endValue($cursor); } + /** + * @return void + */ public function dumpString(Cursor $cursor, string $str, bool $bin, int $cut) { $this->dumpKey($cursor); @@ -260,6 +274,9 @@ public function dumpString(Cursor $cursor, string $str, bool $bin, int $cut) } } + /** + * @return void + */ public function enterHash(Cursor $cursor, int $type, string|int|null $class, bool $hasChild) { $this->colors ??= $this->supportsColors(); @@ -296,6 +313,9 @@ public function enterHash(Cursor $cursor, int $type, string|int|null $class, boo } } + /** + * @return void + */ public function leaveHash(Cursor $cursor, int $type, string|int|null $class, bool $hasChild, int $cut) { if (empty($cursor->attr['cut_hash'])) { @@ -311,6 +331,8 @@ public function leaveHash(Cursor $cursor, int $type, string|int|null $class, boo * * @param bool $hasChild When the dump of the hash has child item * @param int $cut The number of items the hash has been cut by + * + * @return void */ protected function dumpEllipsis(Cursor $cursor, bool $hasChild, int $cut) { @@ -327,6 +349,8 @@ protected function dumpEllipsis(Cursor $cursor, bool $hasChild, int $cut) /** * Dumps a key in a hash structure. + * + * @return void */ protected function dumpKey(Cursor $cursor) { @@ -530,6 +554,9 @@ protected function supportsColors(): bool return static::$defaultColors = $this->hasColorSupport($h); } + /** + * @return void + */ protected function dumpLine(int $depth, bool $endOfValue = false) { if ($this->colors) { @@ -538,6 +565,9 @@ protected function dumpLine(int $depth, bool $endOfValue = false) parent::dumpLine($depth); } + /** + * @return void + */ protected function endValue(Cursor $cursor) { if (-1 === $cursor->hashType) { diff --git a/Dumper/ContextualizedDumper.php b/Dumper/ContextualizedDumper.php index c10cd444..a2e8f8c7 100644 --- a/Dumper/ContextualizedDumper.php +++ b/Dumper/ContextualizedDumper.php @@ -31,6 +31,9 @@ public function __construct(DataDumperInterface $wrappedDumper, array $contextPr $this->contextProviders = $contextProviders; } + /** + * @return void + */ public function dump(Data $data) { $context = $data->getContext(); diff --git a/Dumper/ServerDumper.php b/Dumper/ServerDumper.php index f2c891b6..546490d9 100644 --- a/Dumper/ServerDumper.php +++ b/Dumper/ServerDumper.php @@ -41,6 +41,9 @@ public function getContextProviders(): array return $this->connection->getContextProviders(); } + /** + * @return void + */ public function dump(Data $data) { if (!$this->connection->write($data) && $this->wrappedDumper) { diff --git a/Server/Connection.php b/Server/Connection.php index 23fa456b..692752de 100644 --- a/Server/Connection.php +++ b/Server/Connection.php @@ -62,7 +62,7 @@ public function write(Data $data): bool $context = array_filter($context); $encodedPayload = base64_encode(serialize([$data, $context]))."\n"; - set_error_handler([self::class, 'nullErrorHandler']); + set_error_handler(fn () => true); try { if (-1 !== stream_socket_sendto($this->socket, $encodedPayload)) { return true; @@ -82,17 +82,12 @@ public function write(Data $data): bool return false; } - private static function nullErrorHandler(int $t, string $m) - { - // no-op - } - /** * @psalm-return false|resource */ private function createSocket() { - set_error_handler([self::class, 'nullErrorHandler']); + set_error_handler(fn () => true); try { return stream_socket_client($this->host, $errno, $errstr, 3, \STREAM_CLIENT_CONNECT | \STREAM_CLIENT_ASYNC_CONNECT); } finally { From 4c9dc4deb0565743e5f60e8d38def07be08cf549 Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Wed, 22 Feb 2023 21:03:28 +0100 Subject: [PATCH 12/90] Remove unused private methods --- Tests/Dumper/CliDumperTest.php | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/Tests/Dumper/CliDumperTest.php b/Tests/Dumper/CliDumperTest.php index d2377886..b1eb29eb 100644 --- a/Tests/Dumper/CliDumperTest.php +++ b/Tests/Dumper/CliDumperTest.php @@ -449,22 +449,4 @@ public function testDumpArrayWithColor($value, $flags, $expectedOut) $this->assertSame($expectedOut, $out); } - - private function getSpecialVars() - { - foreach (array_keys($GLOBALS) as $var) { - if ('GLOBALS' !== $var) { - unset($GLOBALS[$var]); - } - } - - $var = function &() { - $var = []; - $var[] = &$var; - - return $var; - }; - - return eval('return [$var(), $GLOBALS, &$GLOBALS];'); - } } From efc8f5d731547a24dd8b3bde3df792bc1ddfd27f Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 20 Mar 2023 16:28:30 +0100 Subject: [PATCH 13/90] [ErrorHandler] Rewrite logic to dump exception properties and fix serializing FlattenException --- Caster/ExceptionCaster.php | 2 +- Cloner/VarCloner.php | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Caster/ExceptionCaster.php b/Caster/ExceptionCaster.php index c58e74a5..d6e0e0dc 100644 --- a/Caster/ExceptionCaster.php +++ b/Caster/ExceptionCaster.php @@ -306,7 +306,7 @@ private static function filterExceptionArray(string $xClass, array $a, string $x if (empty($a[$xPrefix.'previous'])) { unset($a[$xPrefix.'previous']); } - unset($a[$xPrefix.'string'], $a[Caster::PREFIX_DYNAMIC.'xdebug_message'], $a[Caster::PREFIX_DYNAMIC.'__destructorException']); + unset($a[$xPrefix.'string'], $a[Caster::PREFIX_DYNAMIC.'xdebug_message']); if (isset($a[Caster::PREFIX_PROTECTED.'message']) && str_contains($a[Caster::PREFIX_PROTECTED.'message'], "@anonymous\0")) { $a[Caster::PREFIX_PROTECTED.'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]++/', fn ($m) => class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0], $a[Caster::PREFIX_PROTECTED.'message']); diff --git a/Cloner/VarCloner.php b/Cloner/VarCloner.php index 4f5c3471..e168d0d3 100644 --- a/Cloner/VarCloner.php +++ b/Cloner/VarCloner.php @@ -16,7 +16,6 @@ */ class VarCloner extends AbstractCloner { - private static string $gid; private static array $arrayCache = []; protected function doClone(mixed $var): array @@ -41,7 +40,6 @@ protected function doClone(mixed $var): array $stub = null; // Stub capturing the main properties of an original item value // or null if the original value is used directly - $gid = self::$gid ??= hash('xxh128', random_bytes(6)); // Unique string used to detect the special $GLOBALS variable $arrayStub = new Stub(); $arrayStub->type = Stub::TYPE_ARRAY; $fromObjCast = false; From a3ee7dba537c07f45d13e17b387f466bbc74692b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Tue, 28 Mar 2023 19:27:02 +0200 Subject: [PATCH 14/90] [VarDumper] Add Caster::PATTERN_PRIVATE to help builing key --- Caster/Caster.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Caster/Caster.php b/Caster/Caster.php index b6a84fcb..32c69ee0 100644 --- a/Caster/Caster.php +++ b/Caster/Caster.php @@ -36,6 +36,8 @@ class Caster public const PREFIX_VIRTUAL = "\0~\0"; public const PREFIX_DYNAMIC = "\0+\0"; public const PREFIX_PROTECTED = "\0*\0"; + // usage: sprintf(Caster::PATTERN_PRIVATE, $class, $property) + public const PATTERN_PRIVATE = "\0%s\0%s"; /** * Casts objects to arrays and adds the dynamic property prefix. From 7113186e628ed3e6d969b9c49ca26cdd31afcc5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Tue, 28 Mar 2023 19:41:15 +0200 Subject: [PATCH 15/90] [VarDumper] Add a caster for the FlattenException --- Caster/ExceptionCaster.php | 11 ++++++++++ Cloner/AbstractCloner.php | 1 + Tests/Caster/ExceptionCasterTest.php | 30 ++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/Caster/ExceptionCaster.php b/Caster/ExceptionCaster.php index d6e0e0dc..be5a6422 100644 --- a/Caster/ExceptionCaster.php +++ b/Caster/ExceptionCaster.php @@ -11,6 +11,7 @@ namespace Symfony\Component\VarDumper\Caster; +use Symfony\Component\ErrorHandler\Exception\FlattenException; use Symfony\Component\ErrorHandler\Exception\SilencedErrorContext; use Symfony\Component\VarDumper\Cloner\Stub; use Symfony\Component\VarDumper\Exception\ThrowingCasterException; @@ -288,6 +289,16 @@ public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, boo return $a; } + public static function castFlattenException(FlattenException $e, array $a, Stub $stub, bool $isNested) + { + if ($isNested) { + $k = sprintf(Caster::PATTERN_PRIVATE, FlattenException::class, 'traceAsString'); + $a[$k] = new CutStub($a[$k]); + } + + return $a; + } + private static function filterExceptionArray(string $xClass, array $a, string $xPrefix, int $filter): array { if (isset($a[$xPrefix.'trace'])) { diff --git a/Cloner/AbstractCloner.php b/Cloner/AbstractCloner.php index 9df2b79f..6a746b88 100644 --- a/Cloner/AbstractCloner.php +++ b/Cloner/AbstractCloner.php @@ -95,6 +95,7 @@ abstract class AbstractCloner implements ClonerInterface 'Symfony\Component\VarDumper\Caster\TraceStub' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castTraceStub'], 'Symfony\Component\VarDumper\Caster\FrameStub' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castFrameStub'], 'Symfony\Component\VarDumper\Cloner\AbstractCloner' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + 'Symfony\Component\ErrorHandler\Exception\FlattenException' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castFlattenException'], 'Symfony\Component\ErrorHandler\Exception\SilencedErrorContext' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castSilencedErrorContext'], 'Imagine\Image\ImageInterface' => ['Symfony\Component\VarDumper\Caster\ImagineCaster', 'castImage'], diff --git a/Tests/Caster/ExceptionCasterTest.php b/Tests/Caster/ExceptionCasterTest.php index 2609eb7f..15eafecb 100644 --- a/Tests/Caster/ExceptionCasterTest.php +++ b/Tests/Caster/ExceptionCasterTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\VarDumper\Tests\Caster; use PHPUnit\Framework\TestCase; +use Symfony\Component\ErrorHandler\Exception\FlattenException; use Symfony\Component\ErrorHandler\Exception\SilencedErrorContext; use Symfony\Component\VarDumper\Caster\Caster; use Symfony\Component\VarDumper\Caster\ExceptionCaster; @@ -354,4 +355,33 @@ public function testAnonymous() $this->assertDumpMatchesFormat($expectedDump, $e, Caster::EXCLUDE_VERBOSE); } + + /** + * @requires function \Symfony\Component\ErrorHandler\Exception\FlattenException::create + */ + public function testFlattenException() + { + $f = FlattenException::createFromThrowable(new \Exception('Hello')); + + $expectedDump = <<<'EODUMP' +array:1 [ + 0 => Symfony\Component\ErrorHandler\Exception\FlattenException { + -message: "Hello" + -code: 0 + -previous: null + -trace: array:13 %a + -traceAsString: ""…%d + -class: "Exception" + -statusCode: 500 + -statusText: "Internal Server Error" + -headers: [] + -file: "%s/src/Symfony/Component/VarDumper/Tests/Caster/ExceptionCasterTest.php" + -line: %d + -asString: null + } +] +EODUMP; + + $this->assertDumpMatchesFormat($expectedDump, [$f], Caster::EXCLUDE_VERBOSE); + } } From 00eb022c39bf24d98fef1027c10cbe8ca6e2b3d4 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 3 Apr 2023 15:29:57 +0200 Subject: [PATCH 16/90] Fix tests --- Tests/Caster/ExceptionCasterTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Caster/ExceptionCasterTest.php b/Tests/Caster/ExceptionCasterTest.php index 15eafecb..9c615d9f 100644 --- a/Tests/Caster/ExceptionCasterTest.php +++ b/Tests/Caster/ExceptionCasterTest.php @@ -369,7 +369,7 @@ public function testFlattenException() -message: "Hello" -code: 0 -previous: null - -trace: array:13 %a + -trace: array:%d %a -traceAsString: ""…%d -class: "Exception" -statusCode: 500 From cb21bc93f2fe7c0b9859bce455635cfd4658c2f3 Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Wed, 5 Apr 2023 11:41:04 +0200 Subject: [PATCH 17/90] Fix the test for casting FlattenException on Windows The assertion should avoid forcing to show path separators, as done in other tests of the caster, as path separators are different on Windows. --- Tests/Caster/ExceptionCasterTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Caster/ExceptionCasterTest.php b/Tests/Caster/ExceptionCasterTest.php index 9c615d9f..66708944 100644 --- a/Tests/Caster/ExceptionCasterTest.php +++ b/Tests/Caster/ExceptionCasterTest.php @@ -375,7 +375,7 @@ public function testFlattenException() -statusCode: 500 -statusText: "Internal Server Error" -headers: [] - -file: "%s/src/Symfony/Component/VarDumper/Tests/Caster/ExceptionCasterTest.php" + -file: "%sExceptionCasterTest.php" -line: %d -asString: null } From 5767c81c6a9136a67690b82d37e25cb2e507151d Mon Sep 17 00:00:00 2001 From: "alexandre.lassauge" Date: Wed, 12 Apr 2023 14:15:41 +0200 Subject: [PATCH 18/90] [VarDumper] Add missing return types --- Caster/ClassStub.php | 3 +++ Caster/ExceptionCaster.php | 3 +++ Caster/LinkStub.php | 2 +- Caster/StubCaster.php | 3 +++ Cloner/Data.php | 2 +- Cloner/DumperInterface.php | 8 ++++++++ Dumper/CliDumper.php | 2 +- Dumper/ContextualizedDumper.php | 4 ++-- Dumper/DataDumperInterface.php | 4 ++++ Dumper/HtmlDumper.php | 28 +++++++++++++++++++++++++++- Dumper/ServerDumper.php | 6 ++++-- Server/Connection.php | 4 ++-- VarDumper.php | 2 ++ 13 files changed, 61 insertions(+), 10 deletions(-) diff --git a/Caster/ClassStub.php b/Caster/ClassStub.php index f27a17ce..86b44dd2 100644 --- a/Caster/ClassStub.php +++ b/Caster/ClassStub.php @@ -85,6 +85,9 @@ public function __construct(string $identifier, callable|array|string $callable } } + /** + * @return mixed + */ public static function wrapCallable(mixed $callable) { if (\is_object($callable) || !\is_callable($callable)) { diff --git a/Caster/ExceptionCaster.php b/Caster/ExceptionCaster.php index be5a6422..02efb1b0 100644 --- a/Caster/ExceptionCaster.php +++ b/Caster/ExceptionCaster.php @@ -289,6 +289,9 @@ public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, boo return $a; } + /** + * @return array + */ public static function castFlattenException(FlattenException $e, array $a, Stub $stub, bool $isNested) { if ($isNested) { diff --git a/Caster/LinkStub.php b/Caster/LinkStub.php index 4113e3a2..df95f8b0 100644 --- a/Caster/LinkStub.php +++ b/Caster/LinkStub.php @@ -60,7 +60,7 @@ public function __construct(string $label, int $line = 0, string $href = null) } } - private function getComposerRoot(string $file, bool &$inVendor) + private function getComposerRoot(string $file, bool &$inVendor): string|false { if (!isset(self::$vendorRoots)) { self::$vendorRoots = []; diff --git a/Caster/StubCaster.php b/Caster/StubCaster.php index 3fef0569..4b93ff76 100644 --- a/Caster/StubCaster.php +++ b/Caster/StubCaster.php @@ -46,6 +46,9 @@ public static function castStub(Stub $c, array $a, Stub $stub, bool $isNested) return $a; } + /** + * @return array + */ public static function castCutArray(CutArrayStub $c, array $a, Stub $stub, bool $isNested) { return $isNested ? $c->preservedSubset : $a; diff --git a/Cloner/Data.php b/Cloner/Data.php index 056b3dfb..64b595d9 100644 --- a/Cloner/Data.php +++ b/Cloner/Data.php @@ -414,7 +414,7 @@ private function dumpChildren(DumperInterface $dumper, Cursor $parentCursor, arr return $hashCut; } - private function getStub(mixed $item) + private function getStub(mixed $item): mixed { if (!$item || !\is_array($item)) { return $item; diff --git a/Cloner/DumperInterface.php b/Cloner/DumperInterface.php index 61d02d24..4c5b315b 100644 --- a/Cloner/DumperInterface.php +++ b/Cloner/DumperInterface.php @@ -20,6 +20,8 @@ interface DumperInterface { /** * Dumps a scalar value. + * + * @return void */ public function dumpScalar(Cursor $cursor, string $type, string|int|float|bool|null $value); @@ -29,6 +31,8 @@ public function dumpScalar(Cursor $cursor, string $type, string|int|float|bool|n * @param string $str The string being dumped * @param bool $bin Whether $str is UTF-8 or binary encoded * @param int $cut The number of characters $str has been cut by + * + * @return void */ public function dumpString(Cursor $cursor, string $str, bool $bin, int $cut); @@ -38,6 +42,8 @@ public function dumpString(Cursor $cursor, string $str, bool $bin, int $cut); * @param int $type A Cursor::HASH_* const for the type of hash * @param string|int|null $class The object class, resource type or array count * @param bool $hasChild When the dump of the hash has child item + * + * @return void */ public function enterHash(Cursor $cursor, int $type, string|int|null $class, bool $hasChild); @@ -48,6 +54,8 @@ public function enterHash(Cursor $cursor, int $type, string|int|null $class, boo * @param string|int|null $class The object class, resource type or array count * @param bool $hasChild When the dump of the hash has child item * @param int $cut The number of items the hash has been cut by + * + * @return void */ public function leaveHash(Cursor $cursor, int $type, string|int|null $class, bool $hasChild, int $cut); } diff --git a/Dumper/CliDumper.php b/Dumper/CliDumper.php index d04c199e..c337bfed 100644 --- a/Dumper/CliDumper.php +++ b/Dumper/CliDumper.php @@ -648,7 +648,7 @@ private function isWindowsTrueColor(): bool return $result; } - private function getSourceLink(string $file, int $line) + private function getSourceLink(string $file, int $line): string|false { if ($fmt = $this->displayOptions['fileLinkFormat']) { return \is_string($fmt) ? strtr($fmt, ['%f' => $file, '%l' => $line]) : ($fmt->format($file, $line) ?: 'file://'.$file.'#L'.$line); diff --git a/Dumper/ContextualizedDumper.php b/Dumper/ContextualizedDumper.php index a2e8f8c7..84cfb425 100644 --- a/Dumper/ContextualizedDumper.php +++ b/Dumper/ContextualizedDumper.php @@ -32,7 +32,7 @@ public function __construct(DataDumperInterface $wrappedDumper, array $contextPr } /** - * @return void + * @return string|null */ public function dump(Data $data) { @@ -41,6 +41,6 @@ public function dump(Data $data) $context[$contextProvider::class] = $contextProvider->getContext(); } - $this->wrappedDumper->dump($data->withContext($context)); + return $this->wrappedDumper->dump($data->withContext($context)); } } diff --git a/Dumper/DataDumperInterface.php b/Dumper/DataDumperInterface.php index b173bccf..e080aff0 100644 --- a/Dumper/DataDumperInterface.php +++ b/Dumper/DataDumperInterface.php @@ -20,5 +20,9 @@ */ interface DataDumperInterface { + + /** + * @return string|null + */ public function dump(Data $data); } diff --git a/Dumper/HtmlDumper.php b/Dumper/HtmlDumper.php index 91539daa..7ed141e2 100644 --- a/Dumper/HtmlDumper.php +++ b/Dumper/HtmlDumper.php @@ -82,12 +82,18 @@ public function __construct($output = null, string $charset = null, int $flags = $this->styles = static::$themes['dark'] ?? self::$themes['dark']; } + /** + * @return void + */ public function setStyles(array $styles) { $this->headerIsDumped = false; $this->styles = $styles + $this->styles; } + /** + * @return void + */ public function setTheme(string $themeName) { if (!isset(static::$themes[$themeName])) { @@ -101,6 +107,8 @@ public function setTheme(string $themeName) * Configures display options. * * @param array $displayOptions A map of display options to customize the behavior + * + * @return void */ public function setDisplayOptions(array $displayOptions) { @@ -110,6 +118,8 @@ public function setDisplayOptions(array $displayOptions) /** * Sets an HTML header that will be dumped once in the output stream. + * + * @return void */ public function setDumpHeader(?string $header) { @@ -118,6 +128,8 @@ public function setDumpHeader(?string $header) /** * Sets an HTML prefix and suffix that will encapse every single dump. + * + * @return void */ public function setDumpBoundaries(string $prefix, string $suffix) { @@ -136,6 +148,8 @@ public function dump(Data $data, $output = null, array $extraDisplayOptions = [] /** * Dumps the HTML header. + * + * @return string */ protected function getDumpHeader() { @@ -773,6 +787,9 @@ function showCurrent(state) return $this->dumpHeader = preg_replace('/\s+/', ' ', $line).''.$this->dumpHeader; } + /** + * @return void + */ public function dumpString(Cursor $cursor, string $str, bool $bin, int $cut) { if ('' === $str && isset($cursor->attr['img-data'], $cursor->attr['content-type'])) { @@ -788,6 +805,9 @@ public function dumpString(Cursor $cursor, string $str, bool $bin, int $cut) } } + /** + * @return void + */ public function enterHash(Cursor $cursor, int $type, string|int|null $class, bool $hasChild) { if (Cursor::HASH_OBJECT === $type) { @@ -816,6 +836,9 @@ public function enterHash(Cursor $cursor, int $type, string|int|null $class, boo } } + /** + * @return void + */ public function leaveHash(Cursor $cursor, int $type, string|int|null $class, bool $hasChild, int $cut) { $this->dumpEllipsis($cursor, $hasChild, $cut); @@ -923,6 +946,9 @@ protected function style(string $style, string $value, array $attr = []): string return $v; } + /** + * @return void + */ protected function dumpLine(int $depth, bool $endOfValue = false) { if (-1 === $this->lastDepth) { @@ -950,7 +976,7 @@ protected function dumpLine(int $depth, bool $endOfValue = false) AbstractDumper::dumpLine($depth); } - private function getSourceLink(string $file, int $line) + private function getSourceLink(string $file, int $line): string|false { $options = $this->extraDisplayOptions + $this->displayOptions; diff --git a/Dumper/ServerDumper.php b/Dumper/ServerDumper.php index 546490d9..98c21493 100644 --- a/Dumper/ServerDumper.php +++ b/Dumper/ServerDumper.php @@ -42,12 +42,14 @@ public function getContextProviders(): array } /** - * @return void + * @return string|null */ public function dump(Data $data) { if (!$this->connection->write($data) && $this->wrappedDumper) { - $this->wrappedDumper->dump($data); + return $this->wrappedDumper->dump($data); } + + return null; } } diff --git a/Server/Connection.php b/Server/Connection.php index 692752de..e5e62508 100644 --- a/Server/Connection.php +++ b/Server/Connection.php @@ -83,13 +83,13 @@ public function write(Data $data): bool } /** - * @psalm-return false|resource + * @return resource|null */ private function createSocket() { set_error_handler(fn () => true); try { - return stream_socket_client($this->host, $errno, $errstr, 3, \STREAM_CLIENT_CONNECT | \STREAM_CLIENT_ASYNC_CONNECT); + return stream_socket_client($this->host, $errno, $errstr, 3, \STREAM_CLIENT_CONNECT | \STREAM_CLIENT_ASYNC_CONNECT) ?: null; } finally { restore_error_handler(); } diff --git a/VarDumper.php b/VarDumper.php index 7c160166..2e1dad11 100644 --- a/VarDumper.php +++ b/VarDumper.php @@ -39,6 +39,8 @@ class VarDumper /** * @param string|null $label + * + * @return mixed */ public static function dump(mixed $var/* , string $label = null */) { From 3f026afbd79aa419a889126333c25767ef354e09 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 14 Apr 2023 14:13:08 +0200 Subject: [PATCH 19/90] cs fix --- Dumper/DataDumperInterface.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Dumper/DataDumperInterface.php b/Dumper/DataDumperInterface.php index e080aff0..df05b6af 100644 --- a/Dumper/DataDumperInterface.php +++ b/Dumper/DataDumperInterface.php @@ -20,7 +20,6 @@ */ interface DataDumperInterface { - /** * @return string|null */ From 7dbe8a625973f50073fe72410db1c5c66e21198b Mon Sep 17 00:00:00 2001 From: Artyum Petrov <17199757+artyuum@users.noreply.github.com> Date: Thu, 20 Apr 2023 19:24:19 +0400 Subject: [PATCH 20/90] Add "composer require..." in all exception messages when needed --- composer.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/composer.json b/composer.json index 71ec64c0..0c81f0da 100644 --- a/composer.json +++ b/composer.json @@ -30,11 +30,6 @@ "phpunit/phpunit": "<5.4.3", "symfony/console": "<5.4" }, - "suggest": { - "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", - "ext-intl": "To show region name in time zone dump", - "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" - }, "autoload": { "files": [ "Resources/functions/dump.php" ], "psr-4": { "Symfony\\Component\\VarDumper\\": "" }, From b53bbaa9719063f59c08d652b13267ad198fdd43 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Tue, 16 May 2023 12:06:55 +0200 Subject: [PATCH 21/90] [VarDumper] Fix HTML of invisible characters --- Dumper/HtmlDumper.php | 2 +- Tests/Dumper/HtmlDumperTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dumper/HtmlDumper.php b/Dumper/HtmlDumper.php index 7ed141e2..0e56733a 100644 --- a/Dumper/HtmlDumper.php +++ b/Dumper/HtmlDumper.php @@ -928,7 +928,7 @@ protected function style(string $style, string $value, array $attr = []): string if (!($attr['binary'] ?? false)) { $v = preg_replace_callback(static::$unicodeCharsRx, function ($c) { - return '\u{'.strtoupper(dechex(mb_ord($c[0]))).'}'; }, $v); } diff --git a/Tests/Dumper/HtmlDumperTest.php b/Tests/Dumper/HtmlDumperTest.php index 2d0e41e2..13d69f83 100644 --- a/Tests/Dumper/HtmlDumperTest.php +++ b/Tests/Dumper/HtmlDumperTest.php @@ -69,7 +69,7 @@ public function testGet() é\\x01test\\t\\n ing """ - "bo "tebo\\u{FEFF}m" => "te\\u{FEFF}st" "[]" => [] "res" => stream resource @{$res} %A wrapper_type: "plainfile" From 54894d9930a35d225e7046e11d14290c0fa7d5a3 Mon Sep 17 00:00:00 2001 From: Oliver Hader Date: Sat, 8 Apr 2023 10:52:22 +0200 Subject: [PATCH 22/90] [VarDumper] Reduce stylesheet assignments via JavaScript in `HtmlDumper` --- Dumper/HtmlDumper.php | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/Dumper/HtmlDumper.php b/Dumper/HtmlDumper.php index 91539daa..ead2d4ee 100644 --- a/Dumper/HtmlDumper.php +++ b/Dumper/HtmlDumper.php @@ -149,19 +149,17 @@ protected function getDumpHeader() %A', $output->fetch(), 'styles & scripts are output only once'); + $this->assertDoesNotMatchRegularExpression('#(.*)#', $output->fetch(), 'styles & scripts are output only once'); } /** From 41c4628888427967b45f1e967056b5fdd7b922bf Mon Sep 17 00:00:00 2001 From: Nicolas PHILIPPE Date: Mon, 6 May 2024 16:25:16 +0200 Subject: [PATCH 76/90] [VarExporter] fix proxy helper when a method returns null --- Caster/ReflectionCaster.php | 4 ++-- Tests/Caster/ReflectionCasterTest.php | 23 ++++++++++++++++++- .../Php82NullStandaloneReturnType.php | 20 ++++++++++++++++ 3 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 Tests/Fixtures/Php82NullStandaloneReturnType.php diff --git a/Caster/ReflectionCaster.php b/Caster/ReflectionCaster.php index 45397e96..ec09da4f 100644 --- a/Caster/ReflectionCaster.php +++ b/Caster/ReflectionCaster.php @@ -231,7 +231,7 @@ public static function castFunctionAbstract(\ReflectionFunctionAbstract $c, arra if (isset($a[$prefix.'returnType'])) { $v = $a[$prefix.'returnType']; $v = $v instanceof \ReflectionNamedType ? $v->getName() : (string) $v; - $a[$prefix.'returnType'] = new ClassStub($a[$prefix.'returnType'] instanceof \ReflectionNamedType && $a[$prefix.'returnType']->allowsNull() && 'mixed' !== $v ? '?'.$v : $v, [class_exists($v, false) || interface_exists($v, false) || trait_exists($v, false) ? $v : '', '']); + $a[$prefix.'returnType'] = new ClassStub($a[$prefix.'returnType'] instanceof \ReflectionNamedType && $a[$prefix.'returnType']->allowsNull() && !\in_array($v, ['mixed', 'null'], true) ? '?'.$v : $v, [class_exists($v, false) || interface_exists($v, false) || trait_exists($v, false) ? $v : '', '']); } if (isset($a[$prefix.'class'])) { $a[$prefix.'class'] = new ClassStub($a[$prefix.'class']); @@ -413,7 +413,7 @@ public static function getSignature(array $a) if (!$type instanceof \ReflectionNamedType) { $signature .= $type.' '; } else { - if ($param->allowsNull() && 'mixed' !== $type->getName()) { + if ($param->allowsNull() && !\in_array($type->getName(), ['mixed', 'null'], true)) { $signature .= '?'; } $signature .= substr(strrchr('\\'.$type->getName(), '\\'), 1).' '; diff --git a/Tests/Caster/ReflectionCasterTest.php b/Tests/Caster/ReflectionCasterTest.php index eac092f2..10fff190 100644 --- a/Tests/Caster/ReflectionCasterTest.php +++ b/Tests/Caster/ReflectionCasterTest.php @@ -18,6 +18,7 @@ use Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo; use Symfony\Component\VarDumper\Tests\Fixtures\LotsOfAttributes; use Symfony\Component\VarDumper\Tests\Fixtures\NotLoadableClass; +use Symfony\Component\VarDumper\Tests\Fixtures\Php82NullStandaloneReturnType; use Symfony\Component\VarDumper\Tests\Fixtures\ReflectionIntersectionTypeFixture; use Symfony\Component\VarDumper\Tests\Fixtures\ReflectionNamedTypeFixture; use Symfony\Component\VarDumper\Tests\Fixtures\ReflectionUnionTypeFixture; @@ -95,7 +96,7 @@ public function testClosureCaster() $b: & 123 } file: "%sReflectionCasterTest.php" - line: "88 to 88" + line: "%s" } EOTXT , $var @@ -406,6 +407,26 @@ class: "Symfony\Component\VarDumper\Tests\Caster\ReflectionCasterTest" ); } + /** + * @requires PHP 8.2 + */ + public function testNullReturnType() + { + $className = Php82NullStandaloneReturnType::class; + + $this->assertDumpMatchesFormat( + <<foo(...) + ); + } + public function testUnionReturnType() { $f = function (): int|float {}; diff --git a/Tests/Fixtures/Php82NullStandaloneReturnType.php b/Tests/Fixtures/Php82NullStandaloneReturnType.php new file mode 100644 index 00000000..05e8385d --- /dev/null +++ b/Tests/Fixtures/Php82NullStandaloneReturnType.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Tests\Fixtures; + +class Php82NullStandaloneReturnType +{ + public function foo(null $bar): null + { + return null; + } +} From e335c87e025279af10dde66fd62f4d06edd00b89 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 27 May 2024 08:57:07 +0200 Subject: [PATCH 77/90] [VarDumper] Fix generator dump on PHP 8.4 --- Caster/ReflectionCaster.php | 4 +- Tests/Caster/ReflectionCasterTest.php | 82 +++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 2 deletions(-) diff --git a/Caster/ReflectionCaster.php b/Caster/ReflectionCaster.php index 35fd1e8a..87e5ffcc 100644 --- a/Caster/ReflectionCaster.php +++ b/Caster/ReflectionCaster.php @@ -83,13 +83,13 @@ public static function castGenerator(\Generator $c, array $a, Stub $stub, bool $ // Cannot create ReflectionGenerator based on a terminated Generator try { $reflectionGenerator = new \ReflectionGenerator($c); + + return self::castReflectionGenerator($reflectionGenerator, $a, $stub, $isNested); } catch (\Exception $e) { $a[Caster::PREFIX_VIRTUAL.'closed'] = true; return $a; } - - return self::castReflectionGenerator($reflectionGenerator, $a, $stub, $isNested); } public static function castType(\ReflectionType $c, array $a, Stub $stub, bool $isNested) diff --git a/Tests/Caster/ReflectionCasterTest.php b/Tests/Caster/ReflectionCasterTest.php index e5799918..a87fa55c 100644 --- a/Tests/Caster/ReflectionCasterTest.php +++ b/Tests/Caster/ReflectionCasterTest.php @@ -500,6 +500,84 @@ class: "Symfony\Component\VarDumper\Tests\Caster\ReflectionCasterTest" ); } + /** + * @requires PHP < 8.4 + */ + public function testGeneratorPriorTo84() + { + if (\extension_loaded('xdebug')) { + $this->markTestSkipped('xdebug is active'); + } + + $generator = new GeneratorDemo(); + $generator = $generator->baz(); + + $expectedDump = <<<'EODUMP' +Generator { + this: Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo { …} + %s: { + %sGeneratorDemo.php:14 { + Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo->baz() + › { + › yield from bar(); + › } + } +%A} + closed: false +} +EODUMP; + + $this->assertDumpMatchesFormat($expectedDump, $generator); + + foreach ($generator as $v) { + break; + } + + $expectedDump = <<<'EODUMP' +array:2 [ + 0 => ReflectionGenerator { + this: Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo { …} + %s: { + %s%eTests%eFixtures%eGeneratorDemo.php:%d { + Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::foo() +%A › yield 1; +%A } + %s%eTests%eFixtures%eGeneratorDemo.php:20 { …} + %s%eTests%eFixtures%eGeneratorDemo.php:14 { …} +%A } + closed: false + } + 1 => Generator { + %s: { + %s%eTests%eFixtures%eGeneratorDemo.php:%d { + Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::foo() + › yield 1; + › } + › + } +%A } + closed: false + } +] +EODUMP; + + $r = new \ReflectionGenerator($generator); + $this->assertDumpMatchesFormat($expectedDump, [$r, $r->getExecutingGenerator()]); + + foreach ($generator as $v) { + } + + $expectedDump = <<<'EODUMP' +Generator { + closed: true +} +EODUMP; + $this->assertDumpMatchesFormat($expectedDump, $generator); + } + + /** + * @requires PHP 8.4 + */ public function testGenerator() { if (\extension_loaded('xdebug')) { @@ -511,6 +589,7 @@ public function testGenerator() $expectedDump = <<<'EODUMP' Generator { + function: "Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::baz" this: Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo { …} %s: { %sGeneratorDemo.php:14 { @@ -519,6 +598,7 @@ public function testGenerator() › yield from bar(); › } } + Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo->baz() {} %A} closed: false } @@ -545,6 +625,7 @@ public function testGenerator() closed: false } 1 => Generator { + function: "Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::foo" %s: { %s%eTests%eFixtures%eGeneratorDemo.php:%d { Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::foo() @@ -566,6 +647,7 @@ public function testGenerator() $expectedDump = <<<'EODUMP' Generator { + function: "Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::baz" closed: true } EODUMP; From be84ef67ca27b0e45d59e952d8825f9ed212529d Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 28 May 2024 08:40:41 +0200 Subject: [PATCH 78/90] fix tests --- Tests/Caster/ReflectionCasterTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Caster/ReflectionCasterTest.php b/Tests/Caster/ReflectionCasterTest.php index ee662825..70bacf79 100644 --- a/Tests/Caster/ReflectionCasterTest.php +++ b/Tests/Caster/ReflectionCasterTest.php @@ -516,7 +516,7 @@ public function testGeneratorPriorTo84() Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::foo() › yield 1; › } - › + › } %A } closed: false @@ -594,7 +594,7 @@ function: "Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::foo" Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::foo() › yield 1; › } - › + › } %A } closed: false From af8868a6e9d6082dfca11f1a1f205ae93a8b6d93 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 31 May 2024 16:33:22 +0200 Subject: [PATCH 79/90] Revert "minor #54653 Auto-close PRs on subtree-splits (nicolas-grekas)" This reverts commit 2c9352dd91ebaf37b8a3e3c26fd8e1306df2fb73, reversing changes made to 18c3e87f1512be2cc50e90235b144b13bc347258. --- .gitattributes | 3 +- .github/PULL_REQUEST_TEMPLATE.md | 8 ----- .github/workflows/check-subtree-split.yml | 37 ----------------------- 3 files changed, 2 insertions(+), 46 deletions(-) delete mode 100644 .github/PULL_REQUEST_TEMPLATE.md delete mode 100644 .github/workflows/check-subtree-split.yml diff --git a/.gitattributes b/.gitattributes index 14c3c359..84c7add0 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,4 @@ /Tests export-ignore /phpunit.xml.dist export-ignore -/.git* export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 4689c4da..00000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,8 +0,0 @@ -Please do not submit any Pull Requests here. They will be closed. ---- - -Please submit your PR here instead: -https://github.com/symfony/symfony - -This repository is what we call a "subtree split": a read-only subset of that main repository. -We're looking forward to your PR there! diff --git a/.github/workflows/check-subtree-split.yml b/.github/workflows/check-subtree-split.yml deleted file mode 100644 index 16be48ba..00000000 --- a/.github/workflows/check-subtree-split.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: Check subtree split - -on: - pull_request_target: - -jobs: - close-pull-request: - runs-on: ubuntu-latest - - steps: - - name: Close pull request - uses: actions/github-script@v6 - with: - script: | - if (context.repo.owner === "symfony") { - github.rest.issues.createComment({ - owner: "symfony", - repo: context.repo.repo, - issue_number: context.issue.number, - body: ` - Thanks for your Pull Request! We love contributions. - - However, you should instead open your PR on the main repository: - https://github.com/symfony/symfony - - This repository is what we call a "subtree split": a read-only subset of that main repository. - We're looking forward to your PR there! - ` - }); - - github.rest.pulls.update({ - owner: "symfony", - repo: context.repo.repo, - pull_number: context.issue.number, - state: "closed" - }); - } From f82848117a898e1032e413ec910d30a63bc6c3bc Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Thu, 13 Jun 2024 13:09:00 +0200 Subject: [PATCH 80/90] [VarDumper] Fix FFI caster test --- Caster/FFICaster.php | 14 ++++++++++++-- Tests/Caster/FFICasterTest.php | 18 ++---------------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/Caster/FFICaster.php b/Caster/FFICaster.php index f1984eef..ffed9f31 100644 --- a/Caster/FFICaster.php +++ b/Caster/FFICaster.php @@ -115,11 +115,21 @@ private static function castFFIPointer(Stub $stub, CType $type, ?CData $data = n private static function castFFIStringValue(CData $data): string|CutStub { $result = []; + $ffi = \FFI::cdef(<<zend_get_page_size(); + + // get cdata address + $start = $ffi->cast('uintptr_t', $ffi->cast('char*', $data))->cdata; + // accessing memory in the same page as $start is safe + $max = min(self::MAX_STRING_LENGTH, ($start | ($pageSize - 1)) - $start); + + for ($i = 0; $i < $max; ++$i) { $result[$i] = $data[$i]; - if ("\0" === $result[$i]) { + if ("\0" === $data[$i]) { return implode('', $result); } } diff --git a/Tests/Caster/FFICasterTest.php b/Tests/Caster/FFICasterTest.php index 5e7ec147..d06b2996 100644 --- a/Tests/Caster/FFICasterTest.php +++ b/Tests/Caster/FFICasterTest.php @@ -12,7 +12,6 @@ namespace Symfony\Component\VarDumper\Tests\Caster; use PHPUnit\Framework\TestCase; -use Symfony\Component\VarDumper\Caster\FFICaster; use Symfony\Component\VarDumper\Test\VarDumperTestTrait; /** @@ -191,34 +190,21 @@ public function testCastCuttedPointerToChar() PHP, $pointer); } - /** - * It is worth noting that such a test can cause SIGSEGV, as it breaks - * into "foreign" memory. However, this is only theoretical, since - * memory is allocated within the PHP process and almost always "garbage - * data" will be read from the PHP process itself. - * - * If this test fails for some reason, please report it: We may have to - * disable the dumping of strings ("char*") feature in VarDumper. - * - * @see FFICaster::castFFIStringValue() - */ public function testCastNonTrailingCharPointer() { $actualMessage = 'Hello World!'; $actualLength = \strlen($actualMessage); - $string = \FFI::cdef()->new('char['.$actualLength.']'); + $string = \FFI::cdef()->new('char['.($actualLength + 1).']'); $pointer = \FFI::addr($string[0]); - \FFI::memcpy($pointer, $actualMessage, $actualLength); - // Remove automatically addition of the trailing "\0" and remove trailing "\0" $pointer = \FFI::cdef()->cast('char*', \FFI::cdef()->cast('void*', $pointer)); $pointer[$actualLength] = "\x01"; $this->assertDumpMatchesFormat(<< size 8 align 8 { - cdata: "$actualMessage%s" + cdata: %A"$actualMessage%s" } PHP, $pointer); } From c31566e4ca944271cc8d8ac6887cbf31b8c6a172 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Thu, 27 Jun 2024 14:56:10 +0200 Subject: [PATCH 81/90] [VarDumper] Fix `FFICaster` test to be platform-adaptable --- Tests/Caster/FFICasterTest.php | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/Tests/Caster/FFICasterTest.php b/Tests/Caster/FFICasterTest.php index d06b2996..362e0a2c 100644 --- a/Tests/Caster/FFICasterTest.php +++ b/Tests/Caster/FFICasterTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\VarDumper\Tests\Caster; use PHPUnit\Framework\TestCase; +use Symfony\Component\VarDumper\Caster\FFICaster; use Symfony\Component\VarDumper\Test\VarDumperTestTrait; /** @@ -23,6 +24,11 @@ class FFICasterTest extends TestCase { use VarDumperTestTrait; + /** + * @see FFICaster::MAX_STRING_LENGTH + */ + private const MAX_STRING_LENGTH = 255; + protected function setUp(): void { if (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) && 'preload' === \ini_get('ffi.enable')) { @@ -172,17 +178,24 @@ public function testCastCuttedPointerToChar() { $actualMessage = str_repeat('Hello World!', 30)."\0"; $actualLength = \strlen($actualMessage); - - $expectedMessage = 'Hello World!Hello World!Hello World!Hello World!' - .'Hello World!Hello World!Hello World!Hello World!Hello World!Hel' - .'lo World!Hello World!Hello World!Hello World!Hello World!Hello ' - .'World!Hello World!Hello World!Hello World!Hello World!Hello Wor' - .'ld!Hello World!Hel'; + $expectedMessage = substr($actualMessage, 0, self::MAX_STRING_LENGTH); $string = \FFI::cdef()->new('char['.$actualLength.']'); $pointer = \FFI::addr($string[0]); \FFI::memcpy($pointer, $actualMessage, $actualLength); + // the max length is platform-dependent and can be less than 255, + // so we need to cut the expected message to the maximum length + // allowed by pages size of the current system + $ffi = \FFI::cdef(<<zend_get_page_size(); + $start = $ffi->cast('uintptr_t', $ffi->cast('char*', $pointer))->cdata; + $max = min(self::MAX_STRING_LENGTH, ($start | ($pageSize - 1)) - $start); + $expectedMessage = substr($expectedMessage, 0, $max); + $this->assertDumpEquals(<< size 8 align 8 { cdata: "$expectedMessage"… From e4de722fefc6329fc53bec5fcbb53b65e2443e28 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 22 Jul 2024 14:51:40 +0200 Subject: [PATCH 82/90] [ErrorHandler][VarDumper] Remove PHP 8.4 deprecations --- Caster/DOMCaster.php | 9 +-------- Caster/ExceptionCaster.php | 2 +- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/Caster/DOMCaster.php b/Caster/DOMCaster.php index 4dd16e0e..5d933cf7 100644 --- a/Caster/DOMCaster.php +++ b/Caster/DOMCaster.php @@ -23,7 +23,7 @@ class DOMCaster { private const ERROR_CODES = [ - \DOM_PHP_ERR => 'DOM_PHP_ERR', + 0 => 'DOM_PHP_ERR', \DOM_INDEX_SIZE_ERR => 'DOM_INDEX_SIZE_ERR', \DOMSTRING_SIZE_ERR => 'DOMSTRING_SIZE_ERR', \DOM_HIERARCHY_REQUEST_ERR => 'DOM_HIERARCHY_REQUEST_ERR', @@ -138,16 +138,12 @@ public static function castDocument(\DOMDocument $dom, array $a, Stub $stub, boo 'doctype' => $dom->doctype, 'implementation' => $dom->implementation, 'documentElement' => new CutStub($dom->documentElement), - 'actualEncoding' => $dom->actualEncoding, 'encoding' => $dom->encoding, 'xmlEncoding' => $dom->xmlEncoding, - 'standalone' => $dom->standalone, 'xmlStandalone' => $dom->xmlStandalone, - 'version' => $dom->version, 'xmlVersion' => $dom->xmlVersion, 'strictErrorChecking' => $dom->strictErrorChecking, 'documentURI' => $dom->documentURI ? new LinkStub($dom->documentURI) : $dom->documentURI, - 'config' => $dom->config, 'formatOutput' => $dom->formatOutput, 'validateOnParse' => $dom->validateOnParse, 'resolveExternals' => $dom->resolveExternals, @@ -275,9 +271,6 @@ public static function castEntity(\DOMEntity $dom, array $a, Stub $stub, bool $i 'publicId' => $dom->publicId, 'systemId' => $dom->systemId, 'notationName' => $dom->notationName, - 'actualEncoding' => $dom->actualEncoding, - 'encoding' => $dom->encoding, - 'version' => $dom->version, ]; return $a; diff --git a/Caster/ExceptionCaster.php b/Caster/ExceptionCaster.php index 7f5cb65e..d3f5e123 100644 --- a/Caster/ExceptionCaster.php +++ b/Caster/ExceptionCaster.php @@ -41,7 +41,7 @@ class ExceptionCaster \E_USER_ERROR => 'E_USER_ERROR', \E_USER_WARNING => 'E_USER_WARNING', \E_USER_NOTICE => 'E_USER_NOTICE', - \E_STRICT => 'E_STRICT', + 2048 => 'E_STRICT', ]; private static $framesCache = []; From e0a521ee65dd62dfc878fbca159a9d78a52c02ca Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Wed, 24 Jul 2024 10:06:13 +0200 Subject: [PATCH 83/90] [Console][PhpUnitBridge][VarDumper] Fix `NO_COLOR` empty value handling --- Dumper/CliDumper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dumper/CliDumper.php b/Dumper/CliDumper.php index 3e86e4ab..359171b3 100644 --- a/Dumper/CliDumper.php +++ b/Dumper/CliDumper.php @@ -606,7 +606,7 @@ private function hasColorSupport($stream): bool } // Follow https://no-color.org/ - if (isset($_SERVER['NO_COLOR']) || false !== getenv('NO_COLOR')) { + if ('' !== ($_SERVER['NO_COLOR'] ?? getenv('NO_COLOR') ?: '')) { return false; } From 2530d7d5270acd77e9450c2288b800b452e851d3 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 12 Aug 2024 14:42:22 +0200 Subject: [PATCH 84/90] [VarDumper] Fix generator dump format for PHP 8.4 --- Tests/Caster/ReflectionCasterTest.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Tests/Caster/ReflectionCasterTest.php b/Tests/Caster/ReflectionCasterTest.php index a87fa55c..938fb639 100644 --- a/Tests/Caster/ReflectionCasterTest.php +++ b/Tests/Caster/ReflectionCasterTest.php @@ -592,11 +592,11 @@ public function testGenerator() function: "Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::baz" this: Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo { …} %s: { - %sGeneratorDemo.php:14 { + %sGeneratorDemo.php:12 { Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo->baz() + › + › public function baz() › { - › yield from bar(); - › } } Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo->baz() {} %A} @@ -617,7 +617,9 @@ function: "Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::baz" %s: { %s%eTests%eFixtures%eGeneratorDemo.php:%d { Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::foo() -%A › yield 1; + › { + › yield 1; + › } %A } %s%eTests%eFixtures%eGeneratorDemo.php:20 { …} %s%eTests%eFixtures%eGeneratorDemo.php:14 { …} @@ -629,9 +631,9 @@ function: "Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::foo" %s: { %s%eTests%eFixtures%eGeneratorDemo.php:%d { Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::foo() + › { › yield 1; › } - › } %A } closed: false From 5051452846348f5d2fb77ca7a66aa340b5ef14ce Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 13 Aug 2024 15:55:12 +0200 Subject: [PATCH 85/90] [PhpUnitBridge][Console][VarDumper] Fix handling NO_COLOR env var --- Dumper/CliDumper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dumper/CliDumper.php b/Dumper/CliDumper.php index 359171b3..da1d5b2d 100644 --- a/Dumper/CliDumper.php +++ b/Dumper/CliDumper.php @@ -606,7 +606,7 @@ private function hasColorSupport($stream): bool } // Follow https://no-color.org/ - if ('' !== ($_SERVER['NO_COLOR'] ?? getenv('NO_COLOR') ?: '')) { + if ('' !== (($_SERVER['NO_COLOR'] ?? getenv('NO_COLOR'))[0] ?? '')) { return false; } From 04138d92d7bbec95304e593069c2a8e017666d67 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 29 Aug 2024 10:50:20 +0200 Subject: [PATCH 86/90] fix compatibility with Twig 3.12 --- Tests/Fixtures/Twig.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/Fixtures/Twig.php b/Tests/Fixtures/Twig.php index bb6e578d..3d33cad1 100644 --- a/Tests/Fixtures/Twig.php +++ b/Tests/Fixtures/Twig.php @@ -34,17 +34,17 @@ protected function doDisplay(array $context, array $blocks = []) throw new \Exception('Foobar'); } - public function getTemplateName() + public function getTemplateName(): string { return 'foo.twig'; } - public function getDebugInfo() + public function getDebugInfo(): array { return [33 => 1, 34 => 2]; } - public function getSourceContext() + public function getSourceContext(): Twig\Source { return new Twig\Source(" foo bar\n twig source\n\n", 'foo.twig', $this->path ?: __FILE__); } From 6be6a6a8af4818564e3726fc65cf936f34743cef Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 30 Aug 2024 18:01:46 +0200 Subject: [PATCH 87/90] [VarDumper] Fix tests --- Tests/Dumper/CliDumperTest.php | 2 +- Tests/Fixtures/Twig.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Dumper/CliDumperTest.php b/Tests/Dumper/CliDumperTest.php index 918f5f73..ad49e220 100644 --- a/Tests/Dumper/CliDumperTest.php +++ b/Tests/Dumper/CliDumperTest.php @@ -365,7 +365,7 @@ public function testThrowingCaster() #message: "Unexpected Exception thrown from a caster: Foobar" trace: { %sTwig.php:2 { - __TwigTemplate_VarDumperFixture_u75a09->doDisplay(array \$context, array \$blocks = []) + __TwigTemplate_VarDumperFixture_u75a09->doDisplay(array \$context, array \$blocks = []): array › foo bar › twig source › diff --git a/Tests/Fixtures/Twig.php b/Tests/Fixtures/Twig.php index 3d33cad1..e26a3925 100644 --- a/Tests/Fixtures/Twig.php +++ b/Tests/Fixtures/Twig.php @@ -28,7 +28,7 @@ public function __construct(?Twig\Environment $env = null, $path = null) $this->path = $path; } - protected function doDisplay(array $context, array $blocks = []) + protected function doDisplay(array $context, array $blocks = []): array { // line 2 throw new \Exception('Foobar'); From c4a5a08fe8d836a1aeec59eeee9697457fd28723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Mon, 23 Sep 2024 11:24:18 +0200 Subject: [PATCH 88/90] Add PR template and auto-close PR on subtree split repositories --- .gitattributes | 3 +-- .github/PULL_REQUEST_TEMPLATE.md | 8 ++++++++ .github/workflows/close-pull-request.yml | 20 ++++++++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/workflows/close-pull-request.yml diff --git a/.gitattributes b/.gitattributes index 84c7add0..14c3c359 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,3 @@ /Tests export-ignore /phpunit.xml.dist export-ignore -/.gitattributes export-ignore -/.gitignore export-ignore +/.git* export-ignore diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..4689c4da --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,8 @@ +Please do not submit any Pull Requests here. They will be closed. +--- + +Please submit your PR here instead: +https://github.com/symfony/symfony + +This repository is what we call a "subtree split": a read-only subset of that main repository. +We're looking forward to your PR there! diff --git a/.github/workflows/close-pull-request.yml b/.github/workflows/close-pull-request.yml new file mode 100644 index 00000000..e55b4781 --- /dev/null +++ b/.github/workflows/close-pull-request.yml @@ -0,0 +1,20 @@ +name: Close Pull Request + +on: + pull_request_target: + types: [opened] + +jobs: + run: + runs-on: ubuntu-latest + steps: + - uses: superbrothers/close-pull-request@v3 + with: + comment: | + Thanks for your Pull Request! We love contributions. + + However, you should instead open your PR on the main repository: + https://github.com/symfony/symfony + + This repository is what we call a "subtree split": a read-only subset of that main repository. + We're looking forward to your PR there! From 47af4eadb5f956f4e2586bd1abfd5de02c4e2ed4 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 5 Nov 2024 10:27:50 +0100 Subject: [PATCH 89/90] fix detecting anonymous exception classes on Windows and PHP 7 --- Caster/ClassStub.php | 2 +- Caster/ExceptionCaster.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Caster/ClassStub.php b/Caster/ClassStub.php index 48f84835..27c24c9a 100644 --- a/Caster/ClassStub.php +++ b/Caster/ClassStub.php @@ -56,7 +56,7 @@ public function __construct(string $identifier, $callable = null) } if (str_contains($identifier, "@anonymous\0")) { - $this->value = $identifier = 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) { + $this->value = $identifier = 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]; }, $identifier); } diff --git a/Caster/ExceptionCaster.php b/Caster/ExceptionCaster.php index d3f5e123..299f5125 100644 --- a/Caster/ExceptionCaster.php +++ b/Caster/ExceptionCaster.php @@ -288,7 +288,7 @@ private static function filterExceptionArray(string $xClass, array $a, string $x unset($a[$xPrefix.'string'], $a[Caster::PREFIX_DYNAMIC.'xdebug_message'], $a[Caster::PREFIX_DYNAMIC.'__destructorException']); if (isset($a[Caster::PREFIX_PROTECTED.'message']) && str_contains($a[Caster::PREFIX_PROTECTED.'message'], "@anonymous\0")) { - $a[Caster::PREFIX_PROTECTED.'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) { + $a[Caster::PREFIX_PROTECTED.'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]; }, $a[Caster::PREFIX_PROTECTED.'message']); } From 42f18f170aa86d612c3559cfb3bd11a375df32c8 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 8 Nov 2024 14:26:29 +0100 Subject: [PATCH 90/90] relax format assertions for fstat() results on Windows According to https://www.php.net/manual/en/function.stat.php the serial number of the volume that contains the file is returned for the "dev" entry as a 64-bit unsigned integer which may overflow. --- Tests/Caster/SplCasterTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Caster/SplCasterTest.php b/Tests/Caster/SplCasterTest.php index 248e1361..c70d759c 100644 --- a/Tests/Caster/SplCasterTest.php +++ b/Tests/Caster/SplCasterTest.php @@ -104,7 +104,7 @@ public function testCastFileObject() flags: DROP_NEW_LINE|SKIP_EMPTY maxLineLen: 0 fstat: array:26 [ - "dev" => %d + "dev" => %i "ino" => %i "nlink" => %d "rdev" => 0