Description
Symfony version(s) affected
6.2.0 and later
Description
If the LazyProxyTrait is used in a class that extends another class which does not have type declaration "array" for the "$data" parameter of method "__unserialize", PHP rejects the result with an error, e.g.:
Fatal error: Declaration of Symfony\Component\VarExporter\LazyProxyTrait::__unserialize(array $data): void must be compatible with X::__unserialize($data) in .../vendor/symfony/var-exporter/LazyProxyTrait.php on line 322
This for example affects all classes extending ArrayObject from laminas/laminas-stdlib:
https://github.com/laminas/laminas-stdlib/blob/3.20.x/src/ArrayObject.php#L468
e.g. ArrayStorage from laminas/laminas-session.
How to reproduce
<?php
declare(strict_types=1);
use Symfony\Component\VarExporter\LazyProxyTrait;
require __DIR__ . '/../vendor/autoload.php';
class X {
public function __unserialize($data) {}
}
class Y extends X {
use LazyProxyTrait;
}
Possible Solution
Change signature of LazyProxyTrait::__unserialize to remove the parameter type declaration.
As a result, any kind of signature in target classes will be accepted, see https://3v4l.org/QZKi5
Additional Context
Since ProxyHelper::generateLazyProxy generates a string, you can postprocess it as a workaround until this bug is fixed:
<?php
declare(strict_types=1);
use Laminas\Session\Storage\ArrayStorage;
use Symfony\Component\VarExporter\LazyProxyTrait;
use Symfony\Component\VarExporter\ProxyHelper;
require_once __DIR__ . '/../vendor/autoload.php';
trait UntypedLazyProxyTrait {
use LazyProxyTrait { __unserialize as private typed__unserialize; }
public function __unserialize($data): void
{
$this->typed__unserialize($data);
}
}
$proxyCode = ProxyHelper::generateLazyProxy(new ReflectionClass(ArrayStorage::class));
$proxyCode = str_replace(
'use \Symfony\Component\VarExporter\LazyProxyTrait;',
'use UntypedLazyProxyTrait;',
$proxyCode
);
eval('class ArrayStorageProxy'.$proxyCode);