Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Symfony\Component\Cache\Adapter\ArrayAdapter::freeze(): Return value must be of type array|string|int|float|bool|null #51867

Copy link
Copy link
Closed
@motoronik

Description

@motoronik
Issue body actions

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

private function freeze($value, string $key): string|int|float|bool|array|null

But it is possible to return a value that does not correspond to these types - an object.

if ('C' === $serialized[0] || 'O' === $serialized[0] || preg_match('/;[OCRr]:[1-9]/', $serialized)) {
return $serialized;
}

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.