Description
Symfony version(s) affected
6.3.5
Description
After updating to the latest version of Symfony the application was broken. I received a large number of the same errors
[TypeError] Symfony\Component\Cache\Adapter\ArrayAdapter::freeze(): Return value must be of type array|string|int|float|bool|null, MyClassName returned
#1 /var/www/apps/hybrid/vendor/symfony/cache/Adapter/ArrayAdapter.php:328
#2 /var/www/apps/hybrid/vendor/symfony/cache/Adapter/ArrayAdapter.php:177
The problem is that not so long ago a typification of the return value of the freeze method appeared
But it is possible to return a value that does not correspond to these types - an object.
symfony/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php
Lines 323 to 325 in d27190a
If the serialized value does not meet this condition, then an object will be returned that does not match the method's typing.
And since the return type of the method does not support the object, the code will fail.
What happens if enum is serialized
php > enum TestEnum: string { case Test1 = 'test1'; }
php > class TestClass { public string $property1 = '';}
php >
php > $obj = new TestClass();
php > $enum = TestEnum::Test1;
php >
php > var_dump(serialize($obj));
string(43) "O:9:"TestClass":1:{s:9:"property1";s:0:"";}"
php >
php > var_dump(serialize($enum));
string(22) "E:14:"TestEnum:Test1";"
php >
This means that the enum will not match the condition and the enum object itself will be returned and not its serialized representation
How to reproduce
$obj = new TestClass();
$enum = TestEnum::Test1;
$item1 = new CacheItem();
$item1->expiresAt(new \DateTime('now +1 day'));
$item1->set($obj);
$item2 = new CacheItem();
$item2->expiresAt(new \DateTime('now +1 day'));
$item2->set($enum);
$adapter->save($item1);
$adapter->save($item2);
[TypeError] App\Package\Cache\ArrayAdapter::freeze(): Return value must be of type array|string|int|float|bool|null, \TestEnum returned
#1 /var/www/apps/hybrid/app/Package/Cache/ArrayAdapter.php:327
#2 /var/www/apps/hybrid/app/Package/Cache/ArrayAdapter.php:170
Possible Solution
private function freeze(mixed $value, string $key): string|int|float|bool|array|null
{
switch (true) {
case is_null($value):
return 'N;';
case is_string($value):
return ('N;' === $value || (isset($value[2]) && ':' === $value[1]))
? serialize($value)
: $value;
case is_scalar($value):
return $value;
}
try {
return serialize($value);
} catch (\Exception $e) {
unset($this->values[$key], $this->tags[$key]);
$type = get_debug_type($value);
$message = sprintf('Failed to save key "{key}" of type %s: %s', $type, $e->getMessage());
CacheItem::log($this->logger, $message, ['key' => $key, 'exception' => $e, 'cache-adapter' => get_debug_type($this)]);
return null;
}
}
Additional Context
No response