From 9d85c552072b2263baa38d055ffc41006b7debad Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 26 Nov 2024 09:36:21 +0100 Subject: [PATCH] [VarDumper] Add caster for AddressInfo objects --- .../VarDumper/Caster/AddressInfoCaster.php | 80 +++++++++++++++++++ .../Component/VarDumper/Caster/ConstStub.php | 19 +++++ .../VarDumper/Cloner/AbstractCloner.php | 2 + .../Tests/Caster/AddressInfoCasterTest.php | 35 ++++++++ 4 files changed, 136 insertions(+) create mode 100644 src/Symfony/Component/VarDumper/Caster/AddressInfoCaster.php create mode 100644 src/Symfony/Component/VarDumper/Tests/Caster/AddressInfoCasterTest.php diff --git a/src/Symfony/Component/VarDumper/Caster/AddressInfoCaster.php b/src/Symfony/Component/VarDumper/Caster/AddressInfoCaster.php new file mode 100644 index 0000000000000..4ef58960bba44 --- /dev/null +++ b/src/Symfony/Component/VarDumper/Caster/AddressInfoCaster.php @@ -0,0 +1,80 @@ + + * + * 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; + +/** + * @author Nicolas Grekas + */ +final class AddressInfoCaster +{ + private const MAPS = [ + 'ai_flags' => [ + 1 => 'AI_PASSIVE', + 2 => 'AI_CANONNAME', + 4 => 'AI_NUMERICHOST', + 8 => 'AI_V4MAPPED', + 16 => 'AI_ALL', + 32 => 'AI_ADDRCONFIG', + 64 => 'AI_IDN', + 128 => 'AI_CANONIDN', + 1024 => 'AI_NUMERICSERV', + ], + 'ai_family' => [ + 1 => 'AF_UNIX', + 2 => 'AF_INET', + 10 => 'AF_INET6', + 44 => 'AF_DIVERT', + ], + 'ai_socktype' => [ + 1 => 'SOCK_STREAM', + 2 => 'SOCK_DGRAM', + 3 => 'SOCK_RAW', + 4 => 'SOCK_RDM', + 5 => 'SOCK_SEQPACKET', + ], + 'ai_protocol' => [ + 1 => 'SOL_SOCKET', + 6 => 'SOL_TCP', + 17 => 'SOL_UDP', + 136 => 'SOL_UDPLITE', + ], + ]; + + public static function castAddressInfo(\AddressInfo $h, array $a, Stub $stub, bool $isNested): array + { + static $resolvedMaps; + + if (!$resolvedMaps) { + foreach (self::MAPS as $k => $map) { + foreach ($map as $v => $name) { + if (\defined($name)) { + $resolvedMaps[$k][\constant($name)] = $name; + } elseif (!isset($resolvedMaps[$k][$v])) { + $resolvedMaps[$k][$v] = $name; + } + } + } + } + + foreach (socket_addrinfo_explain($h) as $k => $v) { + $a[Caster::PREFIX_VIRTUAL.$k] = match (true) { + 'ai_flags' === $k => ConstStub::fromBitfield($v, $resolvedMaps[$k]), + isset($resolvedMaps[$k][$v]) => new ConstStub($resolvedMaps[$k][$v], $v), + default => $v, + }; + } + + return $a; + } +} diff --git a/src/Symfony/Component/VarDumper/Caster/ConstStub.php b/src/Symfony/Component/VarDumper/Caster/ConstStub.php index 587c6c39867a6..adea7860d19a6 100644 --- a/src/Symfony/Component/VarDumper/Caster/ConstStub.php +++ b/src/Symfony/Component/VarDumper/Caster/ConstStub.php @@ -30,4 +30,23 @@ public function __toString(): string { return (string) $this->value; } + + /** + * @param array $values + */ + public static function fromBitfield(int $value, array $values): self + { + $names = []; + foreach ($values as $v => $name) { + if ($value & $v) { + $names[] = $name; + } + } + + if (!$names) { + $names[] = $values[0] ?? 0; + } + + return new self(implode(' | ', $names), $value); + } } diff --git a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php index 3cd46942b7eb0..d8dcd80a6b7fc 100644 --- a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php @@ -24,6 +24,8 @@ abstract class AbstractCloner implements ClonerInterface public static array $defaultCasters = [ '__PHP_Incomplete_Class' => ['Symfony\Component\VarDumper\Caster\Caster', 'castPhpIncompleteClass'], + 'AddressInfo' => ['Symfony\Component\VarDumper\Caster\AddressInfoCaster', 'castAddressInfo'], + 'Symfony\Component\VarDumper\Caster\CutStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castStub'], 'Symfony\Component\VarDumper\Caster\CutArrayStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castCutArray'], 'Symfony\Component\VarDumper\Caster\ConstStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castStub'], diff --git a/src/Symfony/Component/VarDumper/Tests/Caster/AddressInfoCasterTest.php b/src/Symfony/Component/VarDumper/Tests/Caster/AddressInfoCasterTest.php new file mode 100644 index 0000000000000..1a95ab7e2146d --- /dev/null +++ b/src/Symfony/Component/VarDumper/Tests/Caster/AddressInfoCasterTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Tests\Caster; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\VarDumper\Test\VarDumperTestTrait; + +/** + * @requires extension sockets + */ +class AddressInfoCasterTest extends TestCase +{ + use VarDumperTestTrait; + + public function testCaster() + { + $xDump = <<assertDumpMatchesFormat($xDump, socket_addrinfo_lookup('localhost')[0]); + } +} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy