Description
Symfony version(s) affected
6.3.x
Description
I'm using ext-ds
especially Ds\Map
quite often mainly because the Ds\Map
allows objects as keys.
Unfortunately this breaks the VarDumper in my case triggered by the profiler:
php.CRITICAL: Uncaught Error: Symfony\Component\VarDumper\Caster\DsPairStub::__construct(): Argument #1 ($key) must be of type string|int, App\Entity\GeoCountry given, called in /app/vendor/symfony/var-dumper/Caster/DsCaster.php on line 43 {"exception":"[object] (TypeError(code: 0): Symfony\\Component\\VarDumper\\Caster\\DsPairStub::__construct(): Argument #1 ($key) must be of type string|int, App\\Entity\\\GeoCountry given, called in /app/vendor/symfony/var-dumper/Caster/DsCaster.php on line 43 at /app/vendor/symfony/var-dumper/Caster/DsPairStub.php:21)
[stacktrace]
#0 /app/vendor/symfony/var-dumper/Caster/DsCaster.php(43): Symfony\\Component\\VarDumper\\Caster\\DsPairStub->__construct(Object(App\\Entity\\\GeoCountry), Array)
#1 /app/vendor/symfony/var-dumper/Cloner/AbstractCloner.php(363): Symfony\\Component\\VarDumper\\Caster\\DsCaster::castMap(Object(Ds\\Map), Array, Object(Symfony\\Component\\VarDumper\\Cloner\\Stub), true, 0)
#2 /app/vendor/symfony/var-dumper/Cloner/VarCloner.php(130): Symfony\\Component\\VarDumper\\Cloner\\AbstractCloner->castObject(Object(Symfony\\Component\\VarDumper\\Cloner\\Stub), true)
#3 /app/vendor/symfony/var-dumper/Cloner/AbstractCloner.php(302): Symfony\\Component\\VarDumper\\Cloner\\VarCloner->doClone(Array)
#4 /app/vendor/symfony/http-kernel/DataCollector/DataCollector.php(55): Symfony\\Component\\VarDumper\\Cloner\\AbstractCloner->cloneVar(Array)
#5 /app/vendor/symfony/messenger/DataCollector/MessengerDataCollector.php(47): Symfony\\Component\\HttpKernel\\DataCollector\\DataCollector->cloneVar(Array)
#6 /app/vendor/symfony/http-kernel/Profiler/Profiler.php(100): Symfony\\Component\\Messenger\\DataCollector\\MessengerDataCollector->lateCollect()
#7 /app/vendor/symfony/http-kernel/EventListener/ProfilerListener.php(135): Symfony\\Component\\HttpKernel\\Profiler\\Profiler->saveProfile(Object(Symfony\\Component\\HttpKernel\\Profiler\\Profile))
#8 /app/vendor/symfony/event-dispatcher/Debug/WrappedListener.php(116): Symfony\\Component\\HttpKernel\\EventListener\\ProfilerListener->onKernelTerminate(Object(Symfony\\Component\\HttpKernel\\Event\\TerminateEvent), '...', Object(Symfony\\Component\\HttpKernel\\Debug\\TraceableEventDispatcher))
#9 /app/vendor/symfony/event-dispatcher/EventDispatcher.php(220): Symfony\\Component\\EventDispatcher\\Debug\\WrappedListener->__invoke(Object(Symfony\\Component\\HttpKernel\\Event\\TerminateEvent), '...', Object(Symfony\\Component\\HttpKernel\\Debug\\TraceableEventDispatcher))
#10 /app/vendor/symfony/event-dispatcher/EventDispatcher.php(56): Symfony\\Component\\EventDispatcher\\EventDispatcher->callListeners(Array, '...', Object(Symfony\\Component\\HttpKernel\\Event\\TerminateEvent))
#11 /app/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php(139): Symfony\\Component\\EventDispatcher\\EventDispatcher->dispatch(Object(Symfony\\Component\\HttpKernel\\Event\\TerminateEvent), '...')
#12 /app/vendor/symfony/http-kernel/HttpKernel.php(115): Symfony\\Component\\EventDispatcher\\Debug\\TraceableEventDispatcher->dispatch(Object(Symfony\\Component\\HttpKernel\\Event\\TerminateEvent), '...')
#13 /app/vendor/symfony/http-kernel/Kernel.php(157): Symfony\\Component\\HttpKernel\\HttpKernel->terminate(Object(Symfony\\Component\\HttpFoundation\\Request), Object(Symfony\\Component\\HttpFoundation\\Response))
#14 /app/vendor/symfony/runtime/Runner/Symfony/HttpKernelRunner.php(39): Symfony\\Component\\HttpKernel\\Kernel->terminate(Object(Symfony\\Component\\HttpFoundation\\Request), Object(Symfony\\Component\\HttpFoundation\\Response))
#15 /app/vendor/autoload_runtime.php(29): Symfony\\Component\\Runtime\\Runner\\Symfony\\HttpKernelRunner->run()
#16 /app/public/index.php(7): require_once('...')
#17 {main}
The problem happens in DsCaster::castMap
:
public static function castMap(Map $c, array $a, Stub $stub, bool $isNested): array
{
foreach ($c as $k => $v) {
$a[] = new DsPairStub($k, $v);
}
return $a;
}
... where DsPairStub
accepts only int|string
:
public function __construct(string|int $key, mixed $value)
{
$this->value = [
Caster::PREFIX_VIRTUAL.'key' => $key,
Caster::PREFIX_VIRTUAL.'value' => $value,
];
}
How to reproduce
Create a Ds\Map
, put an object as key and pass it to VarDumper.
Possible Solution
Allow mixed
for the $key
on DsPairStub::construct
- this solves the problem for me but I'm not sure what other implications this might have.
Additional Context
https://www.php.net/manual/en/ds-map.put.php
Keys of type object are supported. If an object implements Ds\Hashable, equality will be determined by the object's equals function. If an object does not implement Ds\Hashable, objects must be references to the same instance to be considered equal.