Skip to content

Commit e3b664d

Browse files
bug symfony#61605 [Cache] Fix internal representation of non-static values (nicolas-grekas)
This PR was merged into the 6.4 branch. Discussion ---------- [Cache] Fix internal representation of non-static values | Q | A | ------------- | --- | Branch? | 6.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Issues | - | License | MIT I'm working on a PR to allow exporting named closures, and the way we use closures in PhpArrayAdapter and PhpFilesAdapter gets into my way. Instead of relying on `instanceof \Closure` checks, this PR adds an internal marker interface. This makes the logic specific to the component, enabling having closures as regular cached values. The new logic is tested since adapters are. Commits ------- a5823af [Cache] Fix internal representation of non-static values
2 parents 3cd859f + a5823af commit e3b664d

File tree

3 files changed

+36
-14
lines changed

3 files changed

+36
-14
lines changed

src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Symfony\Component\Cache\Exception\InvalidArgumentException;
1818
use Symfony\Component\Cache\PruneableInterface;
1919
use Symfony\Component\Cache\ResettableInterface;
20+
use Symfony\Component\Cache\Traits\CachedValueInterface;
2021
use Symfony\Component\Cache\Traits\ContractsTrait;
2122
use Symfony\Component\Cache\Traits\ProxyTrait;
2223
use Symfony\Component\VarExporter\VarExporter;
@@ -96,16 +97,15 @@ public function get(string $key, callable $callback, ?float $beta = null, ?array
9697
if ('N;' === $value) {
9798
return null;
9899
}
100+
if (!$value instanceof CachedValueInterface) {
101+
return $value;
102+
}
99103
try {
100-
if ($value instanceof \Closure) {
101-
return $value();
102-
}
104+
return $value->getValue();
103105
} catch (\Throwable) {
104106
unset($this->keys[$key]);
105107
goto get_from_pool;
106108
}
107-
108-
return $value;
109109
}
110110

111111
public function getItem(mixed $key): CacheItem
@@ -125,9 +125,9 @@ public function getItem(mixed $key): CacheItem
125125

126126
if ('N;' === $value) {
127127
$value = null;
128-
} elseif ($value instanceof \Closure) {
128+
} elseif ($value instanceof CachedValueInterface) {
129129
try {
130-
$value = $value();
130+
$value = $value->getValue();
131131
} catch (\Throwable) {
132132
$value = null;
133133
$isHit = false;
@@ -306,8 +306,7 @@ public function warmUp(array $values): array
306306
}
307307

308308
if (!$isStaticValue) {
309-
$value = str_replace("\n", "\n ", $value);
310-
$value = "static function () {\n return {$value};\n}";
309+
$value = 'new class() implements \\'.CachedValueInterface::class." { public function getValue(): mixed { return {$value}; } }";
311310
}
312311
$hash = hash('xxh128', $value);
313312

@@ -368,9 +367,9 @@ private function generateItems(array $keys): \Generator
368367

369368
if ('N;' === $value) {
370369
yield $key => $f($key, null, true);
371-
} elseif ($value instanceof \Closure) {
370+
} elseif ($value instanceof CachedValueInterface) {
372371
try {
373-
yield $key => $f($key, $value(), true);
372+
yield $key => $f($key, $value->getValue(), true);
374373
} catch (\Throwable) {
375374
yield $key => $f($key, null, false);
376375
}

src/Symfony/Component/Cache/Adapter/PhpFilesAdapter.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Symfony\Component\Cache\Exception\CacheException;
1515
use Symfony\Component\Cache\Exception\InvalidArgumentException;
1616
use Symfony\Component\Cache\PruneableInterface;
17+
use Symfony\Component\Cache\Traits\CachedValueInterface;
1718
use Symfony\Component\Cache\Traits\FilesystemCommonTrait;
1819
use Symfony\Component\VarExporter\VarExporter;
1920

@@ -114,8 +115,10 @@ protected function doFetch(array $ids): iterable
114115
$values[$id] = null;
115116
} elseif (!\is_object($value)) {
116117
$values[$id] = $value;
118+
} elseif ($value instanceof CachedValueInterface) {
119+
$values[$id] = $value->getValue();
117120
} elseif (!$value instanceof LazyValue) {
118-
$values[$id] = $value();
121+
$values[$id] = $value;
119122
} elseif (false === $values[$id] = include $value->file) {
120123
unset($values[$id], $this->values[$id]);
121124
$missingIds[] = $id;
@@ -152,7 +155,7 @@ protected function doFetch(array $ids): iterable
152155
if ($now >= $expiresAt) {
153156
unset($this->values[$id], $missingIds[$k], self::$valuesCache[$file]);
154157
}
155-
} catch (\ErrorException $e) {
158+
} catch (\ErrorException) {
156159
unset($missingIds[$k]);
157160
}
158161
}
@@ -236,7 +239,7 @@ protected function doSave(array $values, int $lifetime): array|bool
236239
if ($isStaticValue) {
237240
$value = "return [{$expiry}, {$value}];";
238241
} elseif ($this->appendOnly) {
239-
$value = "return [{$expiry}, static fn () => {$value}];";
242+
$value = "return [{$expiry}, new class() implements \\".CachedValueInterface::class." { public function getValue(): mixed { return {$value}; } }];";
240243
} else {
241244
// We cannot use a closure here because of https://bugs.php.net/76982
242245
$value = str_replace('\Symfony\Component\VarExporter\Internal\\', '', $value);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Cache\Traits;
13+
14+
/**
15+
* @internal
16+
*/
17+
interface CachedValueInterface
18+
{
19+
public function getValue(): mixed;
20+
}

0 commit comments

Comments
 (0)