From d7425c88c7ce1a90e3a2b0bc95e75b93ea6d03cf Mon Sep 17 00:00:00 2001 From: Dmitrii Derepko Date: Sat, 3 Jun 2023 11:11:40 +0300 Subject: [PATCH 1/7] Dump DateTime-like object individually --- src/VarDumper.php | 20 +- tests/VarDumperTest.php | 1055 ++++++++++++++++++++------------------- 2 files changed, 569 insertions(+), 506 deletions(-) diff --git a/src/VarDumper.php b/src/VarDumper.php index 33095f0..00d51a7 100644 --- a/src/VarDumper.php +++ b/src/VarDumper.php @@ -6,12 +6,13 @@ use __PHP_Incomplete_Class; use Closure; +use DateTimeInterface; use Exception; use IteratorAggregate; use JsonException; use JsonSerializable; -use ReflectionObject; use ReflectionException; +use ReflectionObject; use Yiisoft\Arrays\ArrayableInterface; use function array_keys; @@ -253,6 +254,9 @@ private function dumpInternal($var, bool $format, int $depth, int $level): strin if ($var instanceof Closure) { return $this->exportClosure($var); } + if ($var instanceof DateTimeInterface) { + return $this->exportDateTime($var); + } if ($depth <= $level) { return $this->getObjectDescription($var) . ' (...)'; @@ -319,6 +323,10 @@ private function exportInternal($variable, bool $format, int $level): string if ($variable instanceof Closure) { return $this->exportClosure($variable, $level); } + if ($variable instanceof DateTimeInterface) { + return $this->exportDateTime($variable); + } + $reflectionObject = new ReflectionObject($variable); try { @@ -551,4 +559,14 @@ private function getObjectProperties(object $var): array return (array) $var; } + + private function exportDateTime(DateTimeInterface $variable): string + { + return sprintf( + "new %s('%s', new DateTimeZone('%s'))", + $variable::class, + $variable->format(DateTimeInterface::RFC3339_EXTENDED), + $variable->getTimezone()->getName() + ); + } } diff --git a/tests/VarDumperTest.php b/tests/VarDumperTest.php index 5ac00dd..d5571fd 100644 --- a/tests/VarDumperTest.php +++ b/tests/VarDumperTest.php @@ -4,6 +4,9 @@ namespace Yiisoft\VarDumper\Tests; +use DateTime; +use DateTimeImmutable; +use DateTimeInterface; use DateTimeZone; use PHPUnit\Framework\TestCase; use ReflectionClass; @@ -68,11 +71,22 @@ public function exportDataProvider(): array // @formatter:on $objectWithClosureInPropertyId = spl_object_id($objectWithClosureInProperty); + $dateTime = new DateTime('now'); + $dateTimeInterpretation = $dateTime->format(DateTimeInterface::RFC3339_EXTENDED); + $dateTimeImmutable = new DateTimeImmutable(); + $dateTimeImmutableInterpretation = $dateTimeImmutable->format(DateTimeInterface::RFC3339_EXTENDED); + return [ - 'custom debug info' => [ - $dummyDebugInfo, + 'DateTime object' => [ + $dateTime, + << [ + $dateTimeImmutable, << [ @@ -488,25 +502,16 @@ public function testExportWithClosureArray(): void $this->assertEqualsWithoutLE($expectedResult, $exportResult); } - public function exportWithoutObjectSerializationDataProvider(): array + public static function exportWithoutObjectSerializationDataProvider(): iterable { $dummyDebugInfo = new DummyClass(); $dummyDebugInfo->volume = 10; $dummyDebugInfo->unitPrice = 15; - $params = ['key' => 5]; - $config = ['value' => 5]; - $dummyDebugInfoWithClosure = new DummyClass(); - $dummyDebugInfoWithClosure->volume = 10; - $dummyDebugInfoWithClosure->params = fn () => $params; - $dummyDebugInfoWithClosure->config = fn () => $config; - $dummyDebugInfoWithClosure->unitPrice = 15; - - return [ - 'custom debug info' => [ - $dummyDebugInfo, - [], - << [ + $dummyDebugInfo, + [], + << [ - $dummyDebugInfoWithClosure, - ['$config', '$params'], - << 5]; + $config = ['value' => 5]; + $dummyDebugInfoWithClosure = new DummyClass(); + $dummyDebugInfoWithClosure->volume = 10; + $dummyDebugInfoWithClosure->params = fn () => $params; + $dummyDebugInfoWithClosure->config = fn () => $config; + $dummyDebugInfoWithClosure->unitPrice = 15; + + yield 'custom debug info with use vars' => [ + $dummyDebugInfoWithClosure, + ['$config', '$params'], + <<format(DateTimeInterface::RFC3339_EXTENDED); + + yield 'DateTimeImmutable object' => [ + $dateTimeImmutable, + [], + <<format(DateTimeInterface::RFC3339_EXTENDED); + + yield 'DateTime object' => [ + $dateTime, + [], + <<assertEqualsWithoutLE($result, $output); } - public function asStringDataProvider(): array + public static function asStringDataProvider(): iterable { $dummyDebugInfo = new DummyDebugInfo(); $dummyDebugInfo->volume = 10; $dummyDebugInfo->unitPrice = 15; $dummyDebugInfoObjectId = spl_object_id($dummyDebugInfo); + yield 'custom debug info' => [ + $dummyDebugInfo, + << 10 + [totalPrice] => 150 + ) + S, + ]; + $incompleteObject = unserialize('O:16:"nonExistingClass":0:{}'); $incompleteObjectId = spl_object_id($incompleteObject); + yield 'incomplete object' => [ + $incompleteObject, + << 'nonExistingClass' + ) + S, + ]; + $emptyObject = new stdClass(); $emptyObjectId = spl_object_id($emptyObject); + yield 'empty object' => [ + $emptyObject, + << [ + // @formatter:off + fn () => 1, + // @formatter:on + 'fn () => 1', + ]; + yield 'short static function' => [ + // @formatter:off + static fn () => 1, + // @formatter:on + 'static fn () => 1', + ]; + yield 'function' => [ + function () { + return 1; + }, + 'function () { + return 1; + }', + ]; + yield 'static function' => [ + static function () { + return 1; + }, + 'static function () { + return 1; + }', + ]; + yield 'string' => [ + 'Hello, Yii!', + "'Hello, Yii!'", + ]; + yield 'empty string' => [ + '', + "''", + ]; + yield 'null' => [ + null, + 'null', + ]; + yield 'integer' => [ + 1, + '1', + ]; + yield 'integer with separator' => [ + 1_23_456, + '123456', + ]; + yield 'boolean' => [ + true, + 'true', + ]; + yield 'resource' => [ + fopen('php://input', 'rb'), + '{resource}', + ]; + yield 'empty array' => [ + [], + '[]', + ]; + yield 'array of 3 elements, automatic keys' => [ + [ + 'one', + 'two', + 'three', + ], + << 'one' + 1 => 'two' + 2 => 'three' + ] + S, + ]; + yield 'array of 3 elements, custom keys' => [ + [ + 2 => 'one', + 'two' => 'two', + 0 => 'three', + ], + << 'one' + 'two' => 'two' + 0 => 'three' + ] + S, + ]; + yield 'closure in array' => [ + // @formatter:off + [fn () => new DateTimeZone('')], + // @formatter:on + << fn () => new \DateTimeZone('') + ] + S, + ]; + yield 'original class name' => [ + // @formatter:off + static fn (VarDumper $date) => new DateTimeZone(''), + // @formatter:on + "static fn (\Yiisoft\VarDumper\VarDumper \$date) => new \DateTimeZone('')", + ]; + yield 'class alias' => [ + // @formatter:off + fn (Dumper $date) => new DateTimeZone(''), + // @formatter:on + "fn (\Yiisoft\VarDumper\VarDumper \$date) => new \DateTimeZone('')", + ]; + yield 'namespace alias' => [ + // @formatter:off + fn (VD\VarDumper $date) => new DateTimeZone(''), + // @formatter:on + "fn (\Yiisoft\VarDumper\VarDumper \$date) => new \DateTimeZone('')", + ]; + yield 'closure with null-collision operator' => [ + // @formatter:off + fn () => $_ENV['var'] ?? null, + // @formatter:on + "fn () => \$_ENV['var'] ?? null", + ]; + yield 'utf8 supported' => [ + '🤣', + "'🤣'", + ]; + $objectWithClosureInProperty = new stdClass(); // @formatter:off $objectWithClosureInProperty->a = fn () => 1; // @formatter:on $objectWithClosureInPropertyId = spl_object_id($objectWithClosureInProperty); - return [ - 'custom debug info' => [ - $dummyDebugInfo, - << 10 - [totalPrice] => 150 - ) - S, - ], - 'incomplete object' => [ - $incompleteObject, - << 'nonExistingClass' - ) - S, - ], - 'empty object' => [ - $emptyObject, - << [ - // @formatter:off - fn () => 1, - // @formatter:on - 'fn () => 1', - ], - 'short static function' => [ - // @formatter:off - static fn () => 1, - // @formatter:on - 'static fn () => 1', - ], - 'function' => [ - function () { - return 1; - }, - 'function () { - return 1; - }', - ], - 'static function' => [ - static function () { - return 1; - }, - 'static function () { - return 1; - }', - ], - 'string' => [ - 'Hello, Yii!', - "'Hello, Yii!'", - ], - 'empty string' => [ - '', - "''", - ], - 'null' => [ - null, - 'null', - ], - 'integer' => [ - 1, - '1', - ], - 'integer with separator' => [ - 1_23_456, - '123456', - ], - 'boolean' => [ - true, - 'true', - ], - 'resource' => [ - fopen('php://input', 'rb'), - '{resource}', - ], - 'empty array' => [ - [], - '[]', - ], - 'array of 3 elements, automatic keys' => [ - [ - 'one', - 'two', - 'three', - ], - << 'one' - 1 => 'two' - 2 => 'three' - ] - S, - ], - 'array of 3 elements, custom keys' => [ - [ - 2 => 'one', - 'two' => 'two', - 0 => 'three', - ], - << 'one' - 'two' => 'two' - 0 => 'three' - ] - S, - ], - 'closure in array' => [ - // @formatter:off - [fn () => new DateTimeZone('')], - // @formatter:on - << fn () => new \DateTimeZone('') - ] - S, - ], - 'original class name' => [ - // @formatter:off - static fn (VarDumper $date) => new DateTimeZone(''), - // @formatter:on - "static fn (\Yiisoft\VarDumper\VarDumper \$date) => new \DateTimeZone('')", - ], - 'class alias' => [ - // @formatter:off - fn (Dumper $date) => new DateTimeZone(''), - // @formatter:on - "fn (\Yiisoft\VarDumper\VarDumper \$date) => new \DateTimeZone('')", - ], - 'namespace alias' => [ - // @formatter:off - fn (VD\VarDumper $date) => new DateTimeZone(''), - // @formatter:on - "fn (\Yiisoft\VarDumper\VarDumper \$date) => new \DateTimeZone('')", - ], - 'closure with null-collision operator' => [ - // @formatter:off - fn () => $_ENV['var'] ?? null, - // @formatter:on - "fn () => \$_ENV['var'] ?? null", - ], - 'utf8 supported' => [ - '🤣', - "'🤣'", - ], - 'closure in property supported' => [ - $objectWithClosureInProperty, - << fn () => 1 - ) - S, - ], + + yield 'closure in property supported' => [ + $objectWithClosureInProperty, + << fn () => 1 + ) + S, + ]; + + $dateTime = new DateTime(); + $dateTimeInterpretation = $dateTime->format(DateTimeInterface::RFC3339_EXTENDED); + + yield 'DateTime' => [ + $dateTime, + <<assertEquals($result, $output); } - public function asJsonDataProvider(): array + public static function asJsonDataProvider(): array { $dummyDebugInfo = new DummyDebugInfo(); $dummyDebugInfo->volume = 10; @@ -838,91 +885,91 @@ public function asJsonDataProvider(): array "totalPrice": 150 } JSON, - ], - 'incomplete object' => [ - $incompleteObject, - << [ + $incompleteObject, + << [ - $integerPropertyObject, - << [ + $integerPropertyObject, + << [ - $emptyObject, - << [ + $emptyObject, + << [ - // @formatter:off - fn () => 1, - // @formatter:on - '"fn () => 1"', - ], - 'short static function' => [ - // @formatter:off - static fn () => 1, - // @formatter:on - '"static fn () => 1"', - ], - 'function' => [ - function () { - return 1; - }, - << [ + // @formatter:off + fn () => 1, + // @formatter:on + '"fn () => 1"', + ], + 'short static function' => [ + // @formatter:off + static fn () => 1, + // @formatter:on + '"static fn () => 1"', + ], + 'function' => [ + function () { + return 1; + }, + << [ - static function () { - return 1; - }, - << [ + static function () { + return 1; + }, + << [ - 'Hello, Yii!', - '"Hello, Yii!"', - ], - 'empty string' => [ - '', - '""', - ], - 'null' => [ - null, - 'null', - ], - 'integer' => [ - 1, - '1', - ], - 'integer with separator' => [ - 1_23_456, - '123456', - ], - 'boolean' => [ - true, - 'true', - ], - 'opened resource' => [ - $openedResource, - << [ + 'Hello, Yii!', + '"Hello, Yii!"', + ], + 'empty string' => [ + '', + '""', + ], + 'null' => [ + null, + 'null', + ], + 'integer' => [ + 1, + '1', + ], + 'integer with separator' => [ + 1_23_456, + '123456', + ], + 'boolean' => [ + true, + 'true', + ], + 'opened resource' => [ + $openedResource, + << [ - $closedResource, - << [ + $closedResource, + << [ - [], - '[]', - ], - 'array of 3 elements, automatic keys' => [ - [ - 'one', - 'two', - 'three', - ], - << [ + [], + '[]', + ], + 'array of 3 elements, automatic keys' => [ + [ + 'one', + 'two', + 'three', + ], + << [ - [ - 2 => 'one', - 'two' => 'two', - 0 => 'three', - ], - << [ + [ + 2 => 'one', + 'two' => 'two', + 0 => 'three', + ], + << [ - // @formatter:off - [fn () => new DateTimeZone('')], - // @formatter:on - << [ + // @formatter:off + [fn () => new DateTimeZone('')], + // @formatter:on + << new \\\\DateTimeZone('')" ] JSON, - ], - 'original class name' => [ - // @formatter:off - static fn (VarDumper $date) => new DateTimeZone(''), - // @formatter:on - '"static fn (\\\\Yiisoft\\\\VarDumper\\\\VarDumper $date) => new \\\\DateTimeZone(\'\')"', - ], - 'class alias' => [ - // @formatter:off - fn (Dumper $date) => new DateTimeZone(''), - // @formatter:on - '"fn (\\\\Yiisoft\\\\VarDumper\\\\VarDumper $date) => new \\\\DateTimeZone(\'\')"', - ], - 'namespace alias' => [ - // @formatter:off - fn (VD\VarDumper $date) => new DateTimeZone(''), - // @formatter:on - '"fn (\\\\Yiisoft\\\\VarDumper\\\\VarDumper $date) => new \\\\DateTimeZone(\'\')"', - ], - 'closure with null-collision operator' => [ - // @formatter:off - fn () => $_ENV['var'] ?? null, - // @formatter:on - '"fn () => $_ENV[\'var\'] ?? null"', - ], - 'utf8 supported' => [ - '🤣', - '"\ud83e\udd23"', - ], - 'closure in property supported' => [ - $objectWithClosureInProperty, - << [ + // @formatter:off + static fn (VarDumper $date) => new DateTimeZone(''), + // @formatter:on + '"static fn (\\\\Yiisoft\\\\VarDumper\\\\VarDumper $date) => new \\\\DateTimeZone(\'\')"', + ], + 'class alias' => [ + // @formatter:off + fn (Dumper $date) => new DateTimeZone(''), + // @formatter:on + '"fn (\\\\Yiisoft\\\\VarDumper\\\\VarDumper $date) => new \\\\DateTimeZone(\'\')"', + ], + 'namespace alias' => [ + // @formatter:off + fn (VD\VarDumper $date) => new DateTimeZone(''), + // @formatter:on + '"fn (\\\\Yiisoft\\\\VarDumper\\\\VarDumper $date) => new \\\\DateTimeZone(\'\')"', + ], + 'closure with null-collision operator' => [ + // @formatter:off + fn () => $_ENV['var'] ?? null, + // @formatter:on + '"fn () => $_ENV[\'var\'] ?? null"', + ], + 'utf8 supported' => [ + '🤣', + '"\ud83e\udd23"', + ], + 'closure in property supported' => [ + $objectWithClosureInProperty, + << 1" } JSON, - ], - 'private properties supported' => [ - $objectWithPrivateProperties, - << [ + $objectWithPrivateProperties, + << [ - $nestedObject, - << [ + $nestedObject, + << [ - [ - [ - [ + ], + 'nested array limit' => [ [ - [], + [ + [ + [ + [], + ], + ], + ], ], - ], - ], - ], - <<assertEquals($result, $output); } - public function asPrimitivesDataProvider(): array + public static function asPrimitivesDataProvider(): iterable { $dummyDebugInfo = new DummyDebugInfo(); $dummyDebugInfo->volume = 10; @@ -1136,193 +1183,195 @@ public function asPrimitivesDataProvider(): array $closedResourceId = get_resource_id($closedResource); fclose($closedResource); - return [ - 'custom debug info' => [ - $dummyDebugInfo, - [ - '$__id__$' => $dummyDebugInfoObjectId, - '$__class__$' => DummyDebugInfo::class, - 'volume' => 10, - 'totalPrice' => 150, - ], + yield 'custom debug info' => [ + $dummyDebugInfo, + [ + '$__id__$' => $dummyDebugInfoObjectId, + '$__class__$' => DummyDebugInfo::class, + 'volume' => 10, + 'totalPrice' => 150, ], - 'incomplete object' => [ - $incompleteObject, - [ - '$__id__$' => $incompleteObjectId, - '$__class__$' => '__PHP_Incomplete_Class', - '__PHP_Incomplete_Class_Name' => 'nonExistingClass', - ], + ]; + yield 'incomplete object' => [ + $incompleteObject, + [ + '$__id__$' => $incompleteObjectId, + '$__class__$' => '__PHP_Incomplete_Class', + '__PHP_Incomplete_Class_Name' => 'nonExistingClass', ], - 'integer property object' => [ - $integerPropertyObject, - [ - '$__id__$' => $integerPropertyObjectId, - '$__class__$' => stdClass::class, - '5' => 5, - ], + ]; + yield 'integer property object' => [ + $integerPropertyObject, + [ + '$__id__$' => $integerPropertyObjectId, + '$__class__$' => stdClass::class, + '5' => 5, ], - 'empty object' => [ - $emptyObject, - [ - '$__id__$' => $emptyObjectId, - '$__class__$' => stdClass::class, - ], + ]; + yield 'empty object' => [ + $emptyObject, + [ + '$__id__$' => $emptyObjectId, + '$__class__$' => stdClass::class, ], - 'short function' => [ - // @formatter:off + ]; + yield 'short function' => [ + // @formatter:off fn () => 1, // @formatter:on - 'fn () => 1', - ], - 'short static function' => [ - // @formatter:off + 'fn () => 1', + ]; + yield 'short static function' => [ + // @formatter:off static fn () => 1, // @formatter:on - 'static fn () => 1', - ], - 'function' => [ - function () { - return 1; - }, - 'function () { + 'static fn () => 1', + ]; + yield 'function' => [ + function () { + return 1; + }, + 'function () { return 1; }', - ], - 'static function' => [ - static function () { - return 1; - }, - 'static function () { + ]; + yield 'static function' => [ + static function () { + return 1; + }, + 'static function () { return 1; }', + ]; + yield 'string' => [ + 'Hello, Yii!', + 'Hello, Yii!', + ]; + yield 'empty string' => [ + '', + '', + ]; + yield 'null' => [ + null, + null, + ]; + yield 'integer' => [ + 1, + 1, + ]; + yield 'integer with separator' => [ + 1_23_456, + 123456, + ]; + yield 'boolean' => [ + true, + true, + ]; + yield 'opened resource' => [ + $openedResource, + [ + '$__type__$' => 'resource', + 'id' => $openedResourceId, + 'type' => 'stream', + 'closed' => false, ], - 'string' => [ - 'Hello, Yii!', - 'Hello, Yii!', - ], - 'empty string' => [ - '', - '', - ], - 'null' => [ - null, - null, - ], - 'integer' => [ - 1, - 1, - ], - 'integer with separator' => [ - 1_23_456, - 123456, - ], - 'boolean' => [ - true, - true, - ], - 'opened resource' => [ - $openedResource, - [ - '$__type__$' => 'resource', - 'id' => $openedResourceId, - 'type' => 'stream', - 'closed' => false, - ], + ]; + yield 'closed resource' => [ + $closedResource, + [ + '$__type__$' => 'resource', + 'id' => $closedResourceId, + 'type' => 'Unknown', + 'closed' => true, ], - 'closed resource' => [ - $closedResource, - [ - '$__type__$' => 'resource', - 'id' => $closedResourceId, - 'type' => 'Unknown', - 'closed' => true, - ], + ]; + yield 'empty array' => [ + [], + [], + ]; + yield 'array of 3 elements, automatic keys' => [ + [ + 'one', + 'two', + 'three', ], - 'empty array' => [ - [], - [], + [ + 'one', + 'two', + 'three', ], - 'array of 3 elements, automatic keys' => [ - [ - 'one', - 'two', - 'three', - ], - [ - 'one', - 'two', - 'three', - ], + ]; + yield 'array of 3 elements, custom keys' => [ + [ + 2 => 'one', + 'two' => 'two', + 0 => 'three', ], - 'array of 3 elements, custom keys' => [ - [ - 2 => 'one', - 'two' => 'two', - 0 => 'three', - ], - [ - 2 => 'one', - 'two' => 'two', - 0 => 'three', - ], + [ + 2 => 'one', + 'two' => 'two', + 0 => 'three', ], - 'closure in array' => [ - // @formatter:off + ]; + yield 'closure in array' => [ + // @formatter:off [fn () => new DateTimeZone('')], ["fn () => new \DateTimeZone('')"], - ], - 'original class name' => [ + ]; + yield 'original class name' => [ // @formatter:off static fn (VarDumper $date) => new DateTimeZone(''), // @formatter:on - 'static fn (\Yiisoft\\VarDumper\VarDumper $date) => new \DateTimeZone(\'\')', - ], - 'class alias' => [ - // @formatter:off + 'static fn (\Yiisoft\\VarDumper\VarDumper $date) => new \DateTimeZone(\'\')', + ]; + yield 'class alias' => [ + // @formatter:off fn (Dumper $date) => new DateTimeZone(''), // @formatter:on - 'fn (\Yiisoft\VarDumper\VarDumper $date) => new \DateTimeZone(\'\')', - ], - 'namespace alias' => [ - // @formatter:off + 'fn (\Yiisoft\VarDumper\VarDumper $date) => new \DateTimeZone(\'\')', + ]; + yield 'namespace alias' => [ + // @formatter:off fn (VD\VarDumper $date) => new DateTimeZone(''), // @formatter:on - 'fn (\Yiisoft\VarDumper\VarDumper $date) => new \DateTimeZone(\'\')', - ], - 'closure with null-collision operator' => [ - // @formatter:off + 'fn (\Yiisoft\VarDumper\VarDumper $date) => new \DateTimeZone(\'\')', + ]; + yield 'closure with null-collision operator' => [ + // @formatter:off fn () => $_ENV['var'] ?? null, // @formatter:on - 'fn () => $_ENV[\'var\'] ?? null', - ], - 'utf8 supported' => [ - '🤣', - '🤣', - ], - 'closure in property supported' => [ - $objectWithClosureInProperty, - [ - '$__id__$' => $objectWithClosureInPropertyId, - '$__class__$' => stdClass::class, - 'a' => 'fn () => 1', - ], + 'fn () => $_ENV[\'var\'] ?? null', + ]; + yield 'utf8 supported' => [ + '🤣', + '🤣', + ]; + yield 'closure in property supported' => [ + $objectWithClosureInProperty, + [ + '$__id__$' => $objectWithClosureInPropertyId, + '$__class__$' => stdClass::class, + 'a' => 'fn () => 1', ], - 'private properties supported' => [ - $objectWithPrivateProperties, - [ - '$__id__$' => "$objectWithPrivatePropertiesId", - '$__class__$' => "$objectWithPrivatePropertiesClass", - 'age' => 0, - 'names' => [ - 'first', - 'last', - ], + ]; + yield 'private properties supported' => [ + $objectWithPrivateProperties, + [ + '$__id__$' => "$objectWithPrivatePropertiesId", + '$__class__$' => "$objectWithPrivatePropertiesClass", + 'age' => 0, + 'names' => [ + 'first', + 'last', ], ], - 'nested properties limit' => [ - $nestedObject, - [ + ]; + yield 'nested properties limit' => [ + $nestedObject, + [ + '$__id__$' => "$nestedObjectId", + '$__class__$' => stdClass::class, + 'nested' => [ '$__id__$' => "$nestedObjectId", '$__class__$' => stdClass::class, 'nested' => [ @@ -1331,33 +1380,29 @@ static function () { 'nested' => [ '$__id__$' => "$nestedObjectId", '$__class__$' => stdClass::class, - 'nested' => [ - '$__id__$' => "$nestedObjectId", - '$__class__$' => stdClass::class, - '$__type__$' => 'object', - '$__depth_limit_exceeded__$' => true, - ], + '$__type__$' => 'object', + '$__depth_limit_exceeded__$' => true, ], ], ], ], - 'nested array limit' => [ + ]; + yield 'nested array limit' => [ + [ [ [ [ - [ - [], - ], + [], ], ], ], + ], + [ [ [ [ - [ - '$__type__$' => 'array', - '$__depth_limit_exceeded__$' => true, - ], + '$__type__$' => 'array', + '$__depth_limit_exceeded__$' => true, ], ], ], From 8c083fe4fb399c70c4578f122c75f01fcbc6df30 Mon Sep 17 00:00:00 2001 From: Dmitrii Derepko Date: Sat, 3 Jun 2023 11:57:02 +0300 Subject: [PATCH 2/7] Add tests for DateTime-like objects dump --- src/VarDumper.php | 5 +- tests/VarDumperTest.php | 535 +++++++++++++++++++++------------------- 2 files changed, 284 insertions(+), 256 deletions(-) diff --git a/src/VarDumper.php b/src/VarDumper.php index 00d51a7..9e211c2 100644 --- a/src/VarDumper.php +++ b/src/VarDumper.php @@ -391,6 +391,9 @@ private function exportPrimitives(mixed $var, int $depth, int $level): mixed if ($var instanceof Closure) { return $this->exportClosure($var); } + if ($var instanceof DateTimeInterface) { + return $this->exportDateTime($var); + } $objectClass = get_class($var); $objectId = $this->getObjectId($var); @@ -563,7 +566,7 @@ private function getObjectProperties(object $var): array private function exportDateTime(DateTimeInterface $variable): string { return sprintf( - "new %s('%s', new DateTimeZone('%s'))", + "new \%s('%s', new \DateTimeZone('%s'))", $variable::class, $variable->format(DateTimeInterface::RFC3339_EXTENDED), $variable->getTimezone()->getName() diff --git a/tests/VarDumperTest.php b/tests/VarDumperTest.php index 8c74a16..e87240a 100644 --- a/tests/VarDumperTest.php +++ b/tests/VarDumperTest.php @@ -80,13 +80,13 @@ public function exportDataProvider(): array 'DateTime object' => [ $dateTime, << [ $dateTimeImmutable, << [ @@ -565,7 +565,7 @@ public static function exportWithoutObjectSerializationDataProvider(): iterable $dateTimeImmutable, [], << [ $dateTime, <<assertEquals($result, $output); } - public static function asJsonDataProvider(): array + public static function asJsonDataProvider(): iterable { $dummyDebugInfo = new DummyDebugInfo(); $dummyDebugInfo->volume = 10; $dummyDebugInfo->unitPrice = 15; $dummyDebugInfoObjectId = spl_object_id($dummyDebugInfo); + yield 'custom debug info' => [ + $dummyDebugInfo, + << [ + $incompleteObject, + << [ + $integerPropertyObject, + <<nested = $nestedObject; - $nestedObjectId = spl_object_id($nestedObject); + yield 'empty object' => [ + $emptyObject, + << [ + // @formatter:off + fn () => 1, + // @formatter:on + '"fn () => 1"', + ]; + yield 'short static function' => [ + // @formatter:off + static fn () => 1, + // @formatter:on + '"static fn () => 1"', + ]; + yield 'function' => [ + function () { + return 1; + }, + << [ + static function () { + return 1; + }, + << [ + 'Hello, Yii!', + '"Hello, Yii!"', + ]; + yield 'empty string' => [ + '', + '""', + ]; + yield 'null' => [ + null, + 'null', + ]; + yield 'integer' => [ + 1, + '1', + ]; + yield 'integer with separator' => [ + 1_23_456, + '123456', + ]; + yield 'boolean' => [ + true, + 'true', + ]; + $openedResource = fopen('php://input', 'rb'); + $openedResourceId = get_resource_id($openedResource); + + yield 'opened resource' => [ + $openedResource, + << [ + $closedResource, + << [ + [], + '[]', + ]; + yield 'array of 3 elements, automatic keys' => [ + [ + 'one', + 'two', + 'three', + ], + << [ + [ + 2 => 'one', + 'two' => 'two', + 0 => 'three', + ], + << [ + // @formatter:off + [fn () => new DateTimeZone('')], + // @formatter:on + << new \\\\DateTimeZone('')" + ] + JSON, + ]; + yield 'original class name' => [ + // @formatter:off + static fn (VarDumper $date) => new DateTimeZone(''), + // @formatter:on + '"static fn (\\\\Yiisoft\\\\VarDumper\\\\VarDumper $date) => new \\\\DateTimeZone(\'\')"', + ]; + yield 'class alias' => [ + // @formatter:off + fn (Dumper $date) => new DateTimeZone(''), + // @formatter:on + '"fn (\\\\Yiisoft\\\\VarDumper\\\\VarDumper $date) => new \\\\DateTimeZone(\'\')"', + ]; + yield 'namespace alias' => [ + // @formatter:off + fn (VD\VarDumper $date) => new DateTimeZone(''), + // @formatter:on + '"fn (\\\\Yiisoft\\\\VarDumper\\\\VarDumper $date) => new \\\\DateTimeZone(\'\')"', + ]; + yield 'closure with null-collision operator' => [ + // @formatter:off + fn () => $_ENV['var'] ?? null, + // @formatter:on + '"fn () => $_ENV[\'var\'] ?? null"', + ]; + yield 'utf8 supported' => [ + '🤣', + '"\ud83e\udd23"', + ]; $objectWithClosureInProperty = new stdClass(); // @formatter:off $objectWithClosureInProperty->a = fn () => 1; // @formatter:on $objectWithClosureInPropertyId = spl_object_id($objectWithClosureInProperty); + yield 'closure in property supported' => [ + $objectWithClosureInProperty, + << 1" + } + JSON, + ]; + $objectWithPrivateProperties = new PrivateProperties(); $objectWithPrivatePropertiesId = spl_object_id($objectWithPrivateProperties); $objectWithPrivatePropertiesClass = str_replace('\\', '\\\\', PrivateProperties::class); - $openedResource = fopen('php://input', 'rb'); - $openedResourceId = get_resource_id($openedResource); + yield 'private properties supported' => [ + $objectWithPrivateProperties, + <<nested = $nestedObject; + $nestedObjectId = spl_object_id($nestedObject); - return [ - 'custom debug info' => [ - $dummyDebugInfo, - << [ - $incompleteObject, - << [ - $integerPropertyObject, - << [ - $emptyObject, - << [ - // @formatter:off - fn () => 1, - // @formatter:on - '"fn () => 1"', - ], - 'short static function' => [ - // @formatter:off - static fn () => 1, - // @formatter:on - '"static fn () => 1"', - ], - 'function' => [ - function () { - return 1; - }, - << [ - static function () { - return 1; - }, - << [ - 'Hello, Yii!', - '"Hello, Yii!"', - ], - 'empty string' => [ - '', - '""', - ], - 'null' => [ - null, - 'null', - ], - 'integer' => [ - 1, - '1', - ], - 'integer with separator' => [ - 1_23_456, - '123456', - ], - 'boolean' => [ - true, - 'true', - ], - 'opened resource' => [ - $openedResource, - << [ - $closedResource, - << [ - [], - '[]', - ], - 'array of 3 elements, automatic keys' => [ - [ - 'one', - 'two', - 'three', - ], - << [ - [ - 2 => 'one', - 'two' => 'two', - 0 => 'three', - ], - << [ - // @formatter:off - [fn () => new DateTimeZone('')], - // @formatter:on - << new \\\\DateTimeZone('')" - ] - JSON, - ], - 'original class name' => [ - // @formatter:off - static fn (VarDumper $date) => new DateTimeZone(''), - // @formatter:on - '"static fn (\\\\Yiisoft\\\\VarDumper\\\\VarDumper $date) => new \\\\DateTimeZone(\'\')"', - ], - 'class alias' => [ - // @formatter:off - fn (Dumper $date) => new DateTimeZone(''), - // @formatter:on - '"fn (\\\\Yiisoft\\\\VarDumper\\\\VarDumper $date) => new \\\\DateTimeZone(\'\')"', - ], - 'namespace alias' => [ - // @formatter:off - fn (VD\VarDumper $date) => new DateTimeZone(''), - // @formatter:on - '"fn (\\\\Yiisoft\\\\VarDumper\\\\VarDumper $date) => new \\\\DateTimeZone(\'\')"', - ], - 'closure with null-collision operator' => [ - // @formatter:off - fn () => $_ENV['var'] ?? null, - // @formatter:on - '"fn () => $_ENV[\'var\'] ?? null"', - ], - 'utf8 supported' => [ - '🤣', - '"\ud83e\udd23"', - ], - 'closure in property supported' => [ - $objectWithClosureInProperty, - << 1" - } - JSON, - ], - 'private properties supported' => [ - $objectWithPrivateProperties, - << [ - $nestedObject, - << [ + $nestedObject, + << [ - [ - [ - [ - [ - [], - ], - ], - ], - ], - << [ + [ [ [ [ - { - "\$__type__\$": "array", - "\$__depth_limit_exceeded__\$": true - } - ] + [], + ], + ], + ], + ], + <<format(DateTimeInterface::RFC3339_EXTENDED); + + yield 'DateTime object' => [ + $dateTime, + <<format(DateTimeInterface::RFC3339_EXTENDED); + + yield 'DateTime object' => [ + $dateTime, + << Date: Sat, 3 Jun 2023 12:05:25 +0300 Subject: [PATCH 3/7] Use generator in tests --- tests/VarDumperTest.php | 704 ++++++++++++++++++++-------------------- 1 file changed, 344 insertions(+), 360 deletions(-) diff --git a/tests/VarDumperTest.php b/tests/VarDumperTest.php index e87240a..186a77f 100644 --- a/tests/VarDumperTest.php +++ b/tests/VarDumperTest.php @@ -50,193 +50,185 @@ public function testExport($var, string $expectedResult): void $this->assertEqualsWithoutLE($expectedResult, $exportResult); } - public function exportDataProvider(): array + public static function exportDataProvider(): iterable { - $dummyDebugInfo = new DummyDebugInfo(); - $dummyDebugInfo->volume = 10; - $dummyDebugInfo->unitPrice = 15; - - $incompleteObject = unserialize('O:16:"nonExistingClass":0:{}'); - - $emptyObject = new stdClass(); - - $objectWithReferences1 = new stdClass(); - $objectWithReferences2 = new stdClass(); - $objectWithReferences1->object = $objectWithReferences2; - $objectWithReferences2->object = $objectWithReferences1; - - $objectWithClosureInProperty = new stdClass(); - // @formatter:off - $objectWithClosureInProperty->a = fn () => 1; - // @formatter:on - $objectWithClosureInPropertyId = spl_object_id($objectWithClosureInProperty); - $dateTime = new DateTime('now'); $dateTimeInterpretation = $dateTime->format(DateTimeInterface::RFC3339_EXTENDED); + + yield 'DateTime object' => [ + $dateTime, + <<format(DateTimeInterface::RFC3339_EXTENDED); - return [ - 'DateTime object' => [ - $dateTime, - << [ - $dateTimeImmutable, - << [ + $dateTimeImmutable, + << [ - $incompleteObject, - << [ + $incompleteObject, + << [ - $emptyObject, - << [ + $emptyObject, + << [ + // @formatter:off + fn () => 1, + // @formatter:on + 'fn () => 1', + ]; + yield 'short static function' => [ + // @formatter:off + static fn () => 1, + // @formatter:on + 'static fn () => 1', + ]; + yield 'function' => [ + function () { + return 1; + }, + << [ + static function () { + return 1; + }, + << [ + 'Hello, Yii!', + "'Hello, Yii!'", + ]; + yield 'empty string' => [ + '', + "''", + ]; + yield 'null' => [ + null, + 'null', + ]; + yield 'integer' => [ + 1, + '1', + ]; + yield 'integer with separator' => [ + 1_23_456, + '123456', + ]; + yield 'boolean' => [ + true, + 'true', + ]; + yield 'resource' => [ + fopen('php://input', 'rb'), + 'NULL', + ]; + yield 'empty array' => [ + [], + '[]', + ]; + yield 'array of 3 elements, automatic keys' => [ + [ + 'one', + 'two', + 'three', ], - 'short function' => [ - // @formatter:off - fn () => 1, - // @formatter:on - 'fn () => 1', - ], - 'short static function' => [ - // @formatter:off - static fn () => 1, - // @formatter:on - 'static fn () => 1', - ], - 'function' => [ - function () { - return 1; - }, - << [ - static function () { - return 1; - }, - << [ - 'Hello, Yii!', - "'Hello, Yii!'", - ], - 'empty string' => [ - '', - "''", - ], - 'null' => [ - null, - 'null', - ], - 'integer' => [ - 1, - '1', - ], - 'integer with separator' => [ - 1_23_456, - '123456', - ], - 'boolean' => [ - true, - 'true', - ], - 'resource' => [ - fopen('php://input', 'rb'), - 'NULL', - ], - 'empty array' => [ - [], - '[]', - ], - 'array of 3 elements, automatic keys' => [ - [ - 'one', - 'two', - 'three', - ], - << [ - [ - 2 => 'one', - 'two' => 'two', - 0 => 'three', - ], - << 'one', - 'two' => 'two', - 0 => 'three', - ] - S, - ], - 'closure in array' => [ - // @formatter:off - [fn () => new DateTimeZone('')], - // @formatter:on - << new \DateTimeZone(''), - ] - S, - ], - 'original class name' => [ - // @formatter:off - static fn (VarDumper $date) => new DateTimeZone(''), - // @formatter:on - "static fn (\Yiisoft\VarDumper\VarDumper \$date) => new \DateTimeZone('')", - ], - 'class alias' => [ - // @formatter:off - fn (Dumper $date) => new DateTimeZone(''), - // @formatter:on - "fn (\Yiisoft\VarDumper\VarDumper \$date) => new \DateTimeZone('')", - ], - 'namespace alias' => [ - // @formatter:off - fn (VD\VarDumper $date) => new DateTimeZone(''), - // @formatter:on - "fn (\Yiisoft\VarDumper\VarDumper \$date) => new \DateTimeZone('')", - ], - 'closure with null-collision operator' => [ - // @formatter:off - fn () => $_ENV['var'] ?? null, - // @formatter:on - "fn () => \$_ENV['var'] ?? null", - ], - 'object with references' => [ - $objectWithReferences1, - << [ - '🤣', - "'🤣'", + << [ + [ + 2 => 'one', + 'two' => 'two', + 0 => 'three', ], + << 'one', + 'two' => 'two', + 0 => 'three', + ] + S, + ]; + yield 'closure in array' => [ + // @formatter:off + [fn () => new DateTimeZone('')], + // @formatter:on + << new \DateTimeZone(''), + ] + S, + ]; + yield 'original class name' => [ + // @formatter:off + static fn (VarDumper $date) => new DateTimeZone(''), + // @formatter:on + "static fn (\Yiisoft\VarDumper\VarDumper \$date) => new \DateTimeZone('')", + ]; + yield 'class alias' => [ + // @formatter:off + fn (Dumper $date) => new DateTimeZone(''), + // @formatter:on + "fn (\Yiisoft\VarDumper\VarDumper \$date) => new \DateTimeZone('')", + ]; + yield 'namespace alias' => [ + // @formatter:off + fn (VD\VarDumper $date) => new DateTimeZone(''), + // @formatter:on + "fn (\Yiisoft\VarDumper\VarDumper \$date) => new \DateTimeZone('')", + ]; + yield 'closure with null-collision operator' => [ + // @formatter:off + fn () => $_ENV['var'] ?? null, + // @formatter:on + "fn () => \$_ENV['var'] ?? null", + ]; + + $objectWithReferences1 = new stdClass(); + $objectWithReferences2 = new stdClass(); + $objectWithReferences1->object = $objectWithReferences2; + $objectWithReferences2->object = $objectWithReferences1; + + yield 'object with references' => [ + $objectWithReferences1, + << [ + '🤣', + "'🤣'", ]; } @@ -254,119 +246,117 @@ public function testExportWithoutFormatting($var, string $expectedResult): void $this->assertEqualsWithoutLE($expectedResult, $exportResult); } - public function exportWithoutFormattingDataProvider(): array + public static function exportWithoutFormattingDataProvider(): iterable { - return [ - 'short function' => [ - // @formatter:off - fn () => 1, - // @formatter:on - 'fn () => 1', - ], - 'short static function' => [ - // @formatter:off - static fn () => 1, - // @formatter:on - 'static fn () => 1', - ], - 'function' => [ - function () { - return 1; - }, - << [ - static function () { - return 1; - }, - << [ - 'Hello, Yii!', - "'Hello, Yii!'", - ], - 'empty string' => [ - '', - "''", - ], - 'null' => [ - null, - 'null', - ], - 'integer' => [ - 1, - '1', - ], - 'integer with separator' => [ - 1_23_456, - '123456', - ], - 'boolean' => [ - true, - 'true', - ], - 'resource' => [ - fopen('php://input', 'rb'), - 'NULL', - ], - 'empty array' => [ - [], - '[]', - ], - 'array of 3 elements' => [ - [ - 'one', - 'two', - 'three', - ], - "['one','two','three']", - ], - 'array of 3 elements, custom keys' => [ - [ - 2 => 'one', - 'two' => 'two', - 0 => 'three', - ], - "[2 => 'one','two' => 'two',0 => 'three']", - ], - 'closure in array' => [ - // @formatter:off - [fn () => new DateTimeZone('')], - // @formatter:on - "[fn () => new \DateTimeZone('')]", - ], - 'original class name' => [ - // @formatter:off - fn (VarDumper $date) => new DateTimeZone(''), - // @formatter:on - "fn (\Yiisoft\VarDumper\VarDumper \$date) => new \DateTimeZone('')", - ], - 'class alias' => [ - // @formatter:off - fn (Dumper $date) => new DateTimeZone(''), - // @formatter:on - "fn (\Yiisoft\VarDumper\VarDumper \$date) => new \DateTimeZone('')", - ], - 'namespace alias' => [ - // @formatter:off - fn (VD\VarDumper $date) => new DateTimeZone(''), - // @formatter:on - "fn (\Yiisoft\VarDumper\VarDumper \$date) => new \DateTimeZone('')", + yield 'short function' => [ + // @formatter:off + fn () => 1, + // @formatter:on + 'fn () => 1', + ]; + yield 'short static function' => [ + // @formatter:off + static fn () => 1, + // @formatter:on + 'static fn () => 1', + ]; + yield 'function' => [ + function () { + return 1; + }, + << [ + static function () { + return 1; + }, + << [ + 'Hello, Yii!', + "'Hello, Yii!'", + ]; + yield 'empty string' => [ + '', + "''", + ]; + yield 'null' => [ + null, + 'null', + ]; + yield 'integer' => [ + 1, + '1', + ]; + yield 'integer with separator' => [ + 1_23_456, + '123456', + ]; + yield 'boolean' => [ + true, + 'true', + ]; + yield 'resource' => [ + fopen('php://input', 'rb'), + 'NULL', + ]; + yield 'empty array' => [ + [], + '[]', + ]; + yield 'array of 3 elements' => [ + [ + 'one', + 'two', + 'three', ], - 'closure with null-collision operator' => [ - // @formatter:off - fn () => $_ENV['var'] ?? null, - // @formatter:on - "fn () => \$_ENV['var'] ?? null", + "['one','two','three']", + ]; + yield 'array of 3 elements, custom keys' => [ + [ + 2 => 'one', + 'two' => 'two', + 0 => 'three', ], + "[2 => 'one','two' => 'two',0 => 'three']", + ]; + yield 'closure in array' => [ + // @formatter:off + [fn () => new DateTimeZone('')], + // @formatter:on + "[fn () => new \DateTimeZone('')]", + ]; + yield 'original class name' => [ + // @formatter:off + fn (VarDumper $date) => new DateTimeZone(''), + // @formatter:on + "fn (\Yiisoft\VarDumper\VarDumper \$date) => new \DateTimeZone('')", + ]; + yield 'class alias' => [ + // @formatter:off + fn (Dumper $date) => new DateTimeZone(''), + // @formatter:on + "fn (\Yiisoft\VarDumper\VarDumper \$date) => new \DateTimeZone('')", + ]; + yield 'namespace alias' => [ + // @formatter:off + fn (VD\VarDumper $date) => new DateTimeZone(''), + // @formatter:on + "fn (\Yiisoft\VarDumper\VarDumper \$date) => new \DateTimeZone('')", + ]; + yield 'closure with null-collision operator' => [ + // @formatter:off + fn () => $_ENV['var'] ?? null, + // @formatter:on + "fn () => \$_ENV['var'] ?? null", ]; } @@ -384,14 +374,12 @@ public function testExportWithObjectSerializationFail(object $object, string $ex $this->assertEqualsWithoutLE($expectedResult, $exportResult); } - public function exportWithObjectSerializationFailDataProvider(): array + public static function exportWithObjectSerializationFailDataProvider(): iterable { - return [ - 'Anonymous-instance' => [ - $object = new class () { - }, - var_export(VarDumper::create($object)->asString(), true), - ], + yield 'Anonymous-instance' => [ + $object = new class () { + }, + var_export(VarDumper::create($object)->asString(), true), ]; } @@ -409,78 +397,77 @@ public function testExportObjectWithClosure(object $object, string $expectedResu $this->assertEqualsWithoutLE($expectedResult, $exportResult); } - public function exportObjectWithClosureDataProvider(): array + public static function exportObjectWithClosureDataProvider(): iterable { $objectWithClosureInProperty = new stdClass(); $objectWithClosureInProperty->a = fn () => 1; $objectWithClosureInPropertyId = spl_object_id($objectWithClosureInProperty); - return [ - 'closure in stdClass property' => [ - $objectWithClosureInProperty, - << fn () => 1 - )' - S, - ], - 'ArrayableInterface-instance-with-Closure' => [ - $object = new DummyArrayableWithClosure(), - <<newInstanceWithoutConstructor(); - (function () { - \$this->closure = static fn (): string => __CLASS__; - })->bindTo(\$object, 'Yiisoft\VarDumper\Tests\TestAsset\DummyArrayableWithClosure')(); - - return \$object; - })() - S, - ], - 'JsonSerializable-instance-with-Closure' => [ - $object = new DummyJsonSerializableWithClosure(), - <<newInstanceWithoutConstructor(); - (function () { - \$this->closure = static fn (): string => __CLASS__; - })->bindTo(\$object, 'Yiisoft\VarDumper\Tests\TestAsset\DummyJsonSerializableWithClosure')(); - return \$object; - })() - S, - ], - 'IteratorAggregate-instance-with-Closure' => [ - $object = new DummyIteratorAggregateWithClosure(), - <<newInstanceWithoutConstructor(); - (function () { - \$this->closure = static fn (): string => __CLASS__; - })->bindTo(\$object, 'Yiisoft\VarDumper\Tests\TestAsset\DummyIteratorAggregateWithClosure')(); - - return \$object; - })() - S, - ], - 'Stringable-instance-with-Closure' => [ - $object = new DummyStringableWithClosure(), - <<newInstanceWithoutConstructor(); - (function () { - \$this->closure = static fn (): string => __CLASS__; - })->bindTo(\$object, 'Yiisoft\VarDumper\Tests\TestAsset\DummyStringableWithClosure')(); - - return \$object; - })() - S, - ], + yield 'closure in stdClass property' => [ + $objectWithClosureInProperty, + << fn () => 1 + )' + S, + ]; + yield 'ArrayableInterface-instance-with-Closure' => [ + new DummyArrayableWithClosure(), + <<newInstanceWithoutConstructor(); + (function () { + \$this->closure = static fn (): string => __CLASS__; + })->bindTo(\$object, 'Yiisoft\VarDumper\Tests\TestAsset\DummyArrayableWithClosure')(); + + return \$object; + })() + S, + ]; + yield 'JsonSerializable-instance-with-Closure' => [ + new DummyJsonSerializableWithClosure(), + <<newInstanceWithoutConstructor(); + (function () { + \$this->closure = static fn (): string => __CLASS__; + })->bindTo(\$object, 'Yiisoft\VarDumper\Tests\TestAsset\DummyJsonSerializableWithClosure')(); + + return \$object; + })() + S, + ]; + yield 'IteratorAggregate-instance-with-Closure' => [ + new DummyIteratorAggregateWithClosure(), + <<newInstanceWithoutConstructor(); + (function () { + \$this->closure = static fn (): string => __CLASS__; + })->bindTo(\$object, 'Yiisoft\VarDumper\Tests\TestAsset\DummyIteratorAggregateWithClosure')(); + + return \$object; + })() + S, + ]; + yield 'Stringable-instance-with-Closure' => [ + new DummyStringableWithClosure(), + <<newInstanceWithoutConstructor(); + (function () { + \$this->closure = static fn (): string => __CLASS__; + })->bindTo(\$object, 'Yiisoft\VarDumper\Tests\TestAsset\DummyStringableWithClosure')(); + + return \$object; + })() + S, ]; } @@ -838,12 +825,9 @@ static function () { /** * @dataProvider asJsonDataProvider * - * @param mixed $variable - * @param mixed $result - * * @psalm-suppress MixedAssignment */ - public function testAsJson($variable, $result): void + public function testAsJson($variable, string $result): void { $output = VarDumper::create($variable)->asJson(depth: 3); $this->assertEquals($result, $output); From 19e5e8d1e51a439e42fbb9619bda449887005f36 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Sat, 3 Jun 2023 09:05:47 +0000 Subject: [PATCH 4/7] Apply fixes from StyleCI --- tests/VarDumperTest.php | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/VarDumperTest.php b/tests/VarDumperTest.php index 186a77f..9f3d862 100644 --- a/tests/VarDumperTest.php +++ b/tests/VarDumperTest.php @@ -733,7 +733,7 @@ static function () { 'two', 'three', ], - << 'one' 1 => 'two' @@ -1228,14 +1228,14 @@ public static function asPrimitivesDataProvider(): iterable ]; yield 'short function' => [ // @formatter:off - fn () => 1, - // @formatter:on + fn () => 1, + // @formatter:on 'fn () => 1', ]; yield 'short static function' => [ // @formatter:off - static fn () => 1, - // @formatter:on + static fn () => 1, + // @formatter:on 'static fn () => 1', ]; yield 'function' => [ @@ -1330,31 +1330,31 @@ static function () { ]; yield 'closure in array' => [ // @formatter:off - [fn () => new DateTimeZone('')], - ["fn () => new \DateTimeZone('')"], - ]; - yield 'original class name' => [ - // @formatter:off - static fn (VarDumper $date) => new DateTimeZone(''), - // @formatter:on - 'static fn (\Yiisoft\\VarDumper\VarDumper $date) => new \DateTimeZone(\'\')', - ]; + [fn () => new DateTimeZone('')], + ["fn () => new \DateTimeZone('')"], + ]; + yield 'original class name' => [ + // @formatter:off + static fn (VarDumper $date) => new DateTimeZone(''), + // @formatter:on + 'static fn (\Yiisoft\\VarDumper\VarDumper $date) => new \DateTimeZone(\'\')', + ]; yield 'class alias' => [ // @formatter:off - fn (Dumper $date) => new DateTimeZone(''), - // @formatter:on + fn (Dumper $date) => new DateTimeZone(''), + // @formatter:on 'fn (\Yiisoft\VarDumper\VarDumper $date) => new \DateTimeZone(\'\')', ]; yield 'namespace alias' => [ // @formatter:off - fn (VD\VarDumper $date) => new DateTimeZone(''), - // @formatter:on + fn (VD\VarDumper $date) => new DateTimeZone(''), + // @formatter:on 'fn (\Yiisoft\VarDumper\VarDumper $date) => new \DateTimeZone(\'\')', ]; yield 'closure with null-collision operator' => [ // @formatter:off - fn () => $_ENV['var'] ?? null, - // @formatter:on + fn () => $_ENV['var'] ?? null, + // @formatter:on 'fn () => $_ENV[\'var\'] ?? null', ]; yield 'utf8 supported' => [ From 0b4880eeba8191a9d0d29f1915d328b30267cdda Mon Sep 17 00:00:00 2001 From: Dmitrii Derepko Date: Sat, 3 Jun 2023 12:23:39 +0300 Subject: [PATCH 5/7] Fix primitives dump --- src/VarDumper.php | 3 -- tests/VarDumperTest.php | 78 ++++++++++++++++++++++++++++------------- 2 files changed, 53 insertions(+), 28 deletions(-) diff --git a/src/VarDumper.php b/src/VarDumper.php index 9e211c2..1013bc7 100644 --- a/src/VarDumper.php +++ b/src/VarDumper.php @@ -391,9 +391,6 @@ private function exportPrimitives(mixed $var, int $depth, int $level): mixed if ($var instanceof Closure) { return $this->exportClosure($var); } - if ($var instanceof DateTimeInterface) { - return $this->exportDateTime($var); - } $objectClass = get_class($var); $objectId = $this->getObjectId($var); diff --git a/tests/VarDumperTest.php b/tests/VarDumperTest.php index 186a77f..a219a65 100644 --- a/tests/VarDumperTest.php +++ b/tests/VarDumperTest.php @@ -36,6 +36,21 @@ final class VarDumperTest extends TestCase { + //public function testCreate(): void + //{ + // $variable = new DateTime('now', new DateTimeZone('America/Adak')); + // dd( + // VarDumper::create($variable)->asString(highlight: false), + // VarDumper::create($variable)->asString(highlight: true), + // VarDumper::create($variable)->asPrimitives(), + // VarDumper::create($variable)->asJson(format: false), + // VarDumper::create($variable)->asJson(format: true), + // VarDumper::create($variable)->export(format: false), + // VarDumper::create($variable)->export(format: true), + // ); + //} + const PHP_FORMAT = 'Y-m-d H:i:s.u'; + /** * @dataProvider exportDataProvider * @@ -1133,12 +1148,19 @@ static function () { ]; $dateTime = new DateTime(); - $dateTimeInterpolation = $dateTime->format(DateTimeInterface::RFC3339_EXTENDED); + $dateTimeObjectId = spl_object_id($dateTime); + $dateTimeInterpolation = $dateTime->format(self::PHP_FORMAT); yield 'DateTime object' => [ $dateTime, << [ // @formatter:off - fn () => 1, - // @formatter:on + fn () => 1, + // @formatter:on 'fn () => 1', ]; yield 'short static function' => [ // @formatter:off - static fn () => 1, - // @formatter:on + static fn () => 1, + // @formatter:on 'static fn () => 1', ]; yield 'function' => [ @@ -1330,31 +1352,32 @@ static function () { ]; yield 'closure in array' => [ // @formatter:off - [fn () => new DateTimeZone('')], - ["fn () => new \DateTimeZone('')"], - ]; - yield 'original class name' => [ - // @formatter:off - static fn (VarDumper $date) => new DateTimeZone(''), - // @formatter:on - 'static fn (\Yiisoft\\VarDumper\VarDumper $date) => new \DateTimeZone(\'\')', - ]; + [fn () => new DateTimeZone('')], + // @formatter:on + ["fn () => new \DateTimeZone('')"], + ]; + yield 'original class name' => [ + // @formatter:off + static fn (VarDumper $date) => new DateTimeZone(''), + // @formatter:on + 'static fn (\Yiisoft\\VarDumper\VarDumper $date) => new \DateTimeZone(\'\')', + ]; yield 'class alias' => [ // @formatter:off - fn (Dumper $date) => new DateTimeZone(''), - // @formatter:on + fn (Dumper $date) => new DateTimeZone(''), + // @formatter:on 'fn (\Yiisoft\VarDumper\VarDumper $date) => new \DateTimeZone(\'\')', ]; yield 'namespace alias' => [ // @formatter:off - fn (VD\VarDumper $date) => new DateTimeZone(''), - // @formatter:on + fn (VD\VarDumper $date) => new DateTimeZone(''), + // @formatter:on 'fn (\Yiisoft\VarDumper\VarDumper $date) => new \DateTimeZone(\'\')', ]; yield 'closure with null-collision operator' => [ // @formatter:off - fn () => $_ENV['var'] ?? null, - // @formatter:on + fn () => $_ENV['var'] ?? null, + // @formatter:on 'fn () => $_ENV[\'var\'] ?? null', ]; yield 'utf8 supported' => [ @@ -1425,13 +1448,18 @@ static function () { ]; $dateTime = new DateTime(); - $dateTimeInterpolation = $dateTime->format(DateTimeInterface::RFC3339_EXTENDED); + $dateTimeObjectId = spl_object_id($dateTime); + $dateTimeInterpolation = $dateTime->format(self::PHP_FORMAT); yield 'DateTime object' => [ $dateTime, - << $dateTimeObjectId, + '$__class__$' => DateTime::class, + 'date' => $dateTimeInterpolation, + 'timezone_type' => 3, + 'timezone' => 'UTC', + ], ]; } From 8c16da45a4074f9fbfba805c089b8a81089aa298 Mon Sep 17 00:00:00 2001 From: Dmitrii Derepko Date: Mon, 5 Jun 2023 01:27:51 +0300 Subject: [PATCH 6/7] Add missed constant --- tests/VarDumperTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/VarDumperTest.php b/tests/VarDumperTest.php index 1f4a51b..ee44e67 100644 --- a/tests/VarDumperTest.php +++ b/tests/VarDumperTest.php @@ -36,6 +36,8 @@ final class VarDumperTest extends TestCase { + private const PHP_FORMAT = 'Y-m-d H:i:s.u'; + /** * @dataProvider exportDataProvider * From fecdb0b0b11542e2919e88cd5bba7bdf4b1acbbb Mon Sep 17 00:00:00 2001 From: Dmitrii Derepko Date: Mon, 5 Jun 2023 01:29:57 +0300 Subject: [PATCH 7/7] Add changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2acd0e2..ff2339b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,8 @@ ## 1.5.1 under development -- Enh #88: Removed leading spaces in closure dumps (@xepozz) +- Enh #89: Add individual dumps for `DateTime` and `DateTimeImmutable` objects (@xepozz) +- Enh #88: Remove leading spaces in closure dumps (@xepozz) ## 1.5.0 January 16, 2023