| Total Complexity | 50 | 
| Total Lines | 361 | 
| Duplicated Lines | 0 % | 
| Changes | 1 | ||
| Bugs | 0 | Features | 0 | 
Complex classes like CacheItemPool often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use CacheItemPool, and based on these observations, apply Extract Interface, too.
| 1 | <?php  | 
            ||
| 29 | |||
| 30 | class CacheItemPool implements CacheItemPoolInterface  | 
            ||
| 31 | { | 
            ||
| 32 | /**  | 
            ||
| 33 | * @var CacheInterface  | 
            ||
| 34 | */  | 
            ||
| 35 | protected $pool;  | 
            ||
| 36 | |||
| 37 | /**  | 
            ||
| 38 | * @var Closure needs to be set by class, signature is function(string <key>, mixed <value>, bool <isHit>)  | 
            ||
| 39 | */  | 
            ||
| 40 | private $createCacheItem;  | 
            ||
| 41 | |||
| 42 | /**  | 
            ||
| 43 | * @var Closure needs to be set by class, signature is function(array <deferred>, array <&expiredIds>)  | 
            ||
| 44 | */  | 
            ||
| 45 | private $mergeByLifetime;  | 
            ||
| 46 | |||
| 47 | /** @var array<string,CacheItemInterface> */  | 
            ||
| 48 | private $deferred = [];  | 
            ||
| 49 | |||
| 50 | /** @var array<string,string> */  | 
            ||
| 51 | private $ids = [];  | 
            ||
| 52 | |||
| 53 | /** @var stdclass */  | 
            ||
| 54 | private $miss;  | 
            ||
| 55 | |||
| 56 | /**  | 
            ||
| 57 | * Cache Constructor.  | 
            ||
| 58 | *  | 
            ||
| 59 | * @psalm-suppress InaccessibleProperty  | 
            ||
| 60 | * @psalm-suppress PossiblyUndefinedVariable  | 
            ||
| 61 | *  | 
            ||
| 62 | * @param CacheInterface $psr16  | 
            ||
| 63 | */  | 
            ||
| 64 | public function __construct(CacheInterface $psr16)  | 
            ||
| 65 |     { | 
            ||
| 66 | $this->pool = $psr16;  | 
            ||
| 67 | $this->miss = new stdClass();  | 
            ||
| 68 | |||
| 69 | $this->createCacheItem = Closure::bind(  | 
            ||
| 70 |             static function ($key, $value, $isHit) { | 
            ||
| 71 | $item = new CacheItem();  | 
            ||
| 72 | $item->key = $key;  | 
            ||
| 
                                                                                                    
                        
                         | 
                |||
| 73 | $item->value = $v = $value;  | 
            ||
| 74 | $item->isHit = $isHit;  | 
            ||
| 75 | $item->defaultLifetime = 0;  | 
            ||
| 76 | // Detect wrapped values that encode for their expiry and creation duration  | 
            ||
| 77 | // For compactness, these values are packed in the key of an array using  | 
            ||
| 78 | // magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F  | 
            ||
| 79 | if (  | 
            ||
| 80 | \is_array($v) &&  | 
            ||
| 81 | 1 === \count($v) &&  | 
            ||
| 82 | 10 === \strlen($k = (string) \key($v)) &&  | 
            ||
| 83 | "\x9D" === $k[0] &&  | 
            ||
| 84 | "\0" === $k[5] &&  | 
            ||
| 85 | "\x5F" === $k[9]  | 
            ||
| 86 |                 ) { | 
            ||
| 87 | $item->value = $v[$k];  | 
            ||
| 88 | }  | 
            ||
| 89 | |||
| 90 | return $item;  | 
            ||
| 91 | },  | 
            ||
| 92 | null,  | 
            ||
| 93 | CacheItem::class  | 
            ||
| 94 | );  | 
            ||
| 95 | $getId = Closure::fromCallable([$this, 'getId']);  | 
            ||
| 96 | $this->mergeByLifetime = Closure::bind(  | 
            ||
| 97 |             static function ($deferred, &$expiredIds) use ($getId) { | 
            ||
| 98 | $byLifetime = [];  | 
            ||
| 99 | $now = \microtime(true);  | 
            ||
| 100 | $expiredIds = [];  | 
            ||
| 101 | |||
| 102 |                 foreach ($deferred as $key => $item) { | 
            ||
| 103 | $key = (string) $key;  | 
            ||
| 104 | |||
| 105 |                     if (null === $item->expiry) { | 
            ||
| 106 | $ttl = 0 < $item->defaultLifetime ? $item->defaultLifetime : 0;  | 
            ||
| 107 |                     } elseif (0 >= $ttl = (int) (0.1 + $item->expiry - $now)) { | 
            ||
| 108 | $expiredIds[] = $getId($key);  | 
            ||
| 109 | |||
| 110 | continue;  | 
            ||
| 111 | }  | 
            ||
| 112 | |||
| 113 | // For compactness, expiry and creation duration are packed in the key of an array,  | 
            ||
| 114 | // using magic numbers as separators  | 
            ||
| 115 | $byLifetime[$ttl][$getId($key)] = $item->value;  | 
            ||
| 116 | }  | 
            ||
| 117 | |||
| 118 | return $byLifetime;  | 
            ||
| 119 | },  | 
            ||
| 120 | null,  | 
            ||
| 121 | CacheItem::class  | 
            ||
| 122 | );  | 
            ||
| 123 | }  | 
            ||
| 124 | |||
| 125 | public function __destruct()  | 
            ||
| 126 |     { | 
            ||
| 127 |         if (\count($this->deferred) > 0) { | 
            ||
| 128 | $this->commit();  | 
            ||
| 129 | }  | 
            ||
| 130 | }  | 
            ||
| 131 | |||
| 132 | public function __sleep(): void  | 
            ||
| 135 | }  | 
            ||
| 136 | |||
| 137 | public function __wakeup(): void  | 
            ||
| 138 |     { | 
            ||
| 139 |         throw new BadMethodCallException('Cannot unserialize ' . __CLASS__); | 
            ||
| 140 | }  | 
            ||
| 141 | |||
| 142 | /**  | 
            ||
| 143 |      * {@inheritdoc} | 
            ||
| 144 | */  | 
            ||
| 145 | public function getItem($key)  | 
            ||
| 164 | }  | 
            ||
| 165 | }  | 
            ||
| 166 | |||
| 167 | /**  | 
            ||
| 168 |      * {@inheritdoc} | 
            ||
| 169 | *  | 
            ||
| 170 | * @return array<string,CacheItemInterface>|Traversable  | 
            ||
| 171 | */  | 
            ||
| 172 | public function getItems(array $keys = [])  | 
            ||
| 173 |     { | 
            ||
| 174 |         if (\count($this->deferred) > 0) { | 
            ||
| 175 | $this->commit();  | 
            ||
| 176 | }  | 
            ||
| 177 | $kIds = [];  | 
            ||
| 178 | |||
| 179 |         foreach ($keys as $key) { | 
            ||
| 180 | $kIds[] = $this->getId($key);  | 
            ||
| 181 | }  | 
            ||
| 182 | |||
| 183 | $items = $this->doFetch($kIds);  | 
            ||
| 184 | $kIds = \array_combine($kIds, $keys);  | 
            ||
| 185 | |||
| 186 | return $this->generateItems($items, $kIds);  | 
            ||
| 187 | }  | 
            ||
| 188 | |||
| 189 | /**  | 
            ||
| 190 |      * {@inheritdoc} | 
            ||
| 191 | */  | 
            ||
| 192 | public function hasItem($key)  | 
            ||
| 193 |     { | 
            ||
| 194 | $id = $this->getId($key);  | 
            ||
| 195 | |||
| 196 |         if (isset($this->deferred[$key])) { | 
            ||
| 197 | $this->commit();  | 
            ||
| 198 | }  | 
            ||
| 199 | |||
| 200 | return $this->doHave($id);  | 
            ||
| 201 | }  | 
            ||
| 202 | |||
| 203 | /**  | 
            ||
| 204 |      * {@inheritdoc} | 
            ||
| 205 | */  | 
            ||
| 206 | public function clear()  | 
            ||
| 207 |     { | 
            ||
| 208 | $this->deferred = [];  | 
            ||
| 209 | |||
| 210 | return $this->doClear();  | 
            ||
| 211 | }  | 
            ||
| 212 | |||
| 213 | /**  | 
            ||
| 214 |      * {@inheritdoc} | 
            ||
| 215 | */  | 
            ||
| 216 | public function deleteItem($key)  | 
            ||
| 217 |     { | 
            ||
| 218 | return $this->deleteItems([$key]);  | 
            ||
| 219 | }  | 
            ||
| 220 | |||
| 221 | /**  | 
            ||
| 222 |      * {@inheritdoc} | 
            ||
| 223 | */  | 
            ||
| 224 | public function deleteItems(array $keys)  | 
            ||
| 225 |     { | 
            ||
| 226 | $kIds = [];  | 
            ||
| 227 | |||
| 228 |         foreach ($keys as $key) { | 
            ||
| 229 | $kIds[$key] = $this->getId($key);  | 
            ||
| 230 | unset($this->deferred[$key]);  | 
            ||
| 231 | }  | 
            ||
| 232 | |||
| 233 | return $this->doDelete($kIds);  | 
            ||
| 234 | }  | 
            ||
| 235 | |||
| 236 | /**  | 
            ||
| 237 |      * {@inheritdoc} | 
            ||
| 238 | */  | 
            ||
| 239 | public function save(CacheItemInterface $item)  | 
            ||
| 240 |     { | 
            ||
| 241 | $this->saveDeferred($item);  | 
            ||
| 242 | |||
| 243 | return $this->commit();  | 
            ||
| 244 | }  | 
            ||
| 245 | |||
| 246 | /**  | 
            ||
| 247 |      * {@inheritdoc} | 
            ||
| 248 | */  | 
            ||
| 249 | public function saveDeferred(CacheItemInterface $item)  | 
            ||
| 250 |     { | 
            ||
| 251 | $this->deferred[$item->getKey()] = $item;  | 
            ||
| 252 | |||
| 253 | return true;  | 
            ||
| 254 | }  | 
            ||
| 255 | |||
| 256 | /**  | 
            ||
| 257 |      * {@inheritdoc} | 
            ||
| 258 | */  | 
            ||
| 259 | public function commit()  | 
            ||
| 260 |     { | 
            ||
| 261 | $ok = true;  | 
            ||
| 262 | $byLifetime = $this->mergeByLifetime;  | 
            ||
| 263 | $this->deferred = $expiredIds = [];  | 
            ||
| 264 | $byLifetime = $byLifetime($this->deferred, $expiredIds);  | 
            ||
| 265 | |||
| 266 |         if (\count($expiredIds) > 0) { | 
            ||
| 267 | $this->doDelete($expiredIds);  | 
            ||
| 268 | }  | 
            ||
| 269 | |||
| 270 |         foreach ($byLifetime as $lifetime => $values) { | 
            ||
| 271 |             if ($this->doSave($values, $lifetime)) { | 
            ||
| 272 | continue;  | 
            ||
| 273 | }  | 
            ||
| 274 | |||
| 275 | $ok = false;  | 
            ||
| 276 | }  | 
            ||
| 277 | |||
| 278 | return $ok;  | 
            ||
| 279 | }  | 
            ||
| 280 | |||
| 281 | /**  | 
            ||
| 282 | * Fetches several cache items.  | 
            ||
| 283 | *  | 
            ||
| 284 | * @param array<mixed,string> $ids The cache identifiers to fetch  | 
            ||
| 285 | *  | 
            ||
| 286 | * @return iterable<string,CacheItemInterface> The corresponding values found in the cache  | 
            ||
| 287 | */  | 
            ||
| 288 | protected function doFetch(array $ids)  | 
            ||
| 289 |     { | 
            ||
| 290 | $fetched = $this->pool->getMultiple($ids, $this->miss);  | 
            ||
| 291 | |||
| 292 |         if ($fetched instanceof Generator) { | 
            ||
| 293 | $fetched = $fetched->getReturn();  | 
            ||
| 294 | }  | 
            ||
| 295 | |||
| 296 |         foreach ($fetched as $key => $value) { | 
            ||
| 297 |             if ($this->miss !== $value) { | 
            ||
| 298 | yield $key => $value;  | 
            ||
| 299 | }  | 
            ||
| 300 | }  | 
            ||
| 301 | }  | 
            ||
| 302 | |||
| 303 | /**  | 
            ||
| 304 | * Confirms if the cache contains specified cache item.  | 
            ||
| 305 | *  | 
            ||
| 306 | * @param string $id The identifier for which to check existence  | 
            ||
| 307 | *  | 
            ||
| 308 | * @return bool True if item exists in the cache, false otherwise  | 
            ||
| 309 | */  | 
            ||
| 310 | protected function doHave(string $id)  | 
            ||
| 311 |     { | 
            ||
| 312 | return $this->pool->has($id);  | 
            ||
| 313 | }  | 
            ||
| 314 | |||
| 315 | /**  | 
            ||
| 316 | * Deletes all items in the pool.  | 
            ||
| 317 | *  | 
            ||
| 318 | * @return bool True if the pool was successfully cleared, false otherwise  | 
            ||
| 319 | */  | 
            ||
| 320 | protected function doClear()  | 
            ||
| 321 |     { | 
            ||
| 322 | return $this->pool->clear();  | 
            ||
| 323 | }  | 
            ||
| 324 | |||
| 325 | /**  | 
            ||
| 326 | * Removes multiple items from the pool.  | 
            ||
| 327 | *  | 
            ||
| 328 | * @param array<string,string> $ids An array of identifiers that should be removed from the pool  | 
            ||
| 329 | *  | 
            ||
| 330 | * @return bool True if the items were successfully removed, false otherwise  | 
            ||
| 331 | */  | 
            ||
| 332 | protected function doDelete(array $ids)  | 
            ||
| 335 | }  | 
            ||
| 336 | |||
| 337 | /**  | 
            ||
| 338 | * Persists several cache items immediately.  | 
            ||
| 339 | *  | 
            ||
| 340 | * @param array<string,mixed> $values The values to cache, indexed by their cache identifier  | 
            ||
| 341 | * @param int $lifetime The lifetime of the cached values, 0 for persisting until manual cleaning  | 
            ||
| 342 | *  | 
            ||
| 343 | * @return bool a boolean stating if caching succeeded or not  | 
            ||
| 344 | */  | 
            ||
| 345 | protected function doSave(array $values, int $lifetime)  | 
            ||
| 346 |     { | 
            ||
| 347 | return $this->pool->setMultiple($values, 0 === $lifetime ? null : $lifetime);  | 
            ||
| 348 | }  | 
            ||
| 349 | |||
| 350 | /**  | 
            ||
| 351 | * @param iterable<string,mixed> $items  | 
            ||
| 352 | * @param array<string,string> $keys  | 
            ||
| 353 | *  | 
            ||
| 354 | * @return array<string,CacheItemInterface>|Traversable  | 
            ||
| 355 | */  | 
            ||
| 356 | private function generateItems(iterable $items, array &$keys)  | 
            ||
| 357 |     { | 
            ||
| 358 | $f = $this->createCacheItem;  | 
            ||
| 359 | |||
| 360 |         foreach ($items as $id => $value) { | 
            ||
| 361 |             if (!isset($keys[$id])) { | 
            ||
| 362 | $id = \key($keys);  | 
            ||
| 363 | }  | 
            ||
| 364 | $key = $keys[$id];  | 
            ||
| 365 | unset($keys[$id]);  | 
            ||
| 366 | |||
| 367 | yield $key => $f($key, $value, true);  | 
            ||
| 368 | }  | 
            ||
| 369 | |||
| 370 |         foreach ($keys as $key) { | 
            ||
| 371 | yield $key => $f($key, null, false);  | 
            ||
| 372 | }  | 
            ||
| 373 | }  | 
            ||
| 374 | |||
| 375 | /**  | 
            ||
| 376 | * @param mixed $key  | 
            ||
| 377 | *  | 
            ||
| 378 | * @return string  | 
            ||
| 379 | */  | 
            ||
| 380 | private function getId($key)  | 
            ||
| 389 | }  | 
            ||
| 390 | }  | 
            ||
| 391 |