vendor/symfony/symfony/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php line 93

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\Cache\Adapter;
  11. use Psr\Cache\CacheItemInterface;
  12. use Psr\Cache\CacheItemPoolInterface;
  13. use Symfony\Component\Cache\CacheItem;
  14. use Symfony\Component\Cache\Exception\InvalidArgumentException;
  15. use Symfony\Component\Cache\PruneableInterface;
  16. use Symfony\Component\Cache\ResettableInterface;
  17. use Symfony\Component\Cache\Traits\PhpArrayTrait;
  18. /**
  19.  * Caches items at warm up time using a PHP array that is stored in shared memory by OPCache since PHP 7.0.
  20.  * Warmed up items are read-only and run-time discovered items are cached using a fallback adapter.
  21.  *
  22.  * @author Titouan Galopin <galopintitouan@gmail.com>
  23.  * @author Nicolas Grekas <p@tchwork.com>
  24.  */
  25. class PhpArrayAdapter implements AdapterInterfacePruneableInterfaceResettableInterface
  26. {
  27.     use PhpArrayTrait;
  28.     private $createCacheItem;
  29.     /**
  30.      * @param string           $file         The PHP file were values are cached
  31.      * @param AdapterInterface $fallbackPool A pool to fallback on when an item is not hit
  32.      */
  33.     public function __construct($fileAdapterInterface $fallbackPool)
  34.     {
  35.         $this->file $file;
  36.         $this->pool $fallbackPool;
  37.         $this->zendDetectUnicode filter_var(ini_get('zend.detect_unicode'), \FILTER_VALIDATE_BOOLEAN);
  38.         $this->createCacheItem = \Closure::bind(
  39.             static function ($key$value$isHit) {
  40.                 $item = new CacheItem();
  41.                 $item->key $key;
  42.                 $item->value $value;
  43.                 $item->isHit $isHit;
  44.                 return $item;
  45.             },
  46.             null,
  47.             CacheItem::class
  48.         );
  49.     }
  50.     /**
  51.      * This adapter should only be used on PHP 7.0+ to take advantage of how PHP
  52.      * stores arrays in its latest versions. This factory method decorates the given
  53.      * fallback pool with this adapter only if the current PHP version is supported.
  54.      *
  55.      * @param string                 $file         The PHP file were values are cached
  56.      * @param CacheItemPoolInterface $fallbackPool A pool to fallback on when an item is not hit
  57.      *
  58.      * @return CacheItemPoolInterface
  59.      */
  60.     public static function create($fileCacheItemPoolInterface $fallbackPool)
  61.     {
  62.         if (\PHP_VERSION_ID >= 70000) {
  63.             if (!$fallbackPool instanceof AdapterInterface) {
  64.                 $fallbackPool = new ProxyAdapter($fallbackPool);
  65.             }
  66.             return new static($file$fallbackPool);
  67.         }
  68.         return $fallbackPool;
  69.     }
  70.     /**
  71.      * {@inheritdoc}
  72.      */
  73.     public function getItem($key)
  74.     {
  75.         if (!\is_string($key)) {
  76.             throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
  77.         }
  78.         if (null === $this->values) {
  79.             $this->initialize();
  80.         }
  81.         if (!isset($this->values[$key])) {
  82.             return $this->pool->getItem($key);
  83.         }
  84.         $value $this->values[$key];
  85.         $isHit true;
  86.         if ('N;' === $value) {
  87.             $value null;
  88.         } elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
  89.             try {
  90.                 $e null;
  91.                 $value unserialize($value);
  92.             } catch (\Error $e) {
  93.             } catch (\Exception $e) {
  94.             }
  95.             if (null !== $e) {
  96.                 $value null;
  97.                 $isHit false;
  98.             }
  99.         }
  100.         $f $this->createCacheItem;
  101.         return $f($key$value$isHit);
  102.     }
  103.     /**
  104.      * {@inheritdoc}
  105.      */
  106.     public function getItems(array $keys = [])
  107.     {
  108.         foreach ($keys as $key) {
  109.             if (!\is_string($key)) {
  110.                 throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
  111.             }
  112.         }
  113.         if (null === $this->values) {
  114.             $this->initialize();
  115.         }
  116.         return $this->generateItems($keys);
  117.     }
  118.     /**
  119.      * {@inheritdoc}
  120.      */
  121.     public function hasItem($key)
  122.     {
  123.         if (!\is_string($key)) {
  124.             throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
  125.         }
  126.         if (null === $this->values) {
  127.             $this->initialize();
  128.         }
  129.         return isset($this->values[$key]) || $this->pool->hasItem($key);
  130.     }
  131.     /**
  132.      * {@inheritdoc}
  133.      */
  134.     public function deleteItem($key)
  135.     {
  136.         if (!\is_string($key)) {
  137.             throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
  138.         }
  139.         if (null === $this->values) {
  140.             $this->initialize();
  141.         }
  142.         return !isset($this->values[$key]) && $this->pool->deleteItem($key);
  143.     }
  144.     /**
  145.      * {@inheritdoc}
  146.      */
  147.     public function deleteItems(array $keys)
  148.     {
  149.         $deleted true;
  150.         $fallbackKeys = [];
  151.         foreach ($keys as $key) {
  152.             if (!\is_string($key)) {
  153.                 throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
  154.             }
  155.             if (isset($this->values[$key])) {
  156.                 $deleted false;
  157.             } else {
  158.                 $fallbackKeys[] = $key;
  159.             }
  160.         }
  161.         if (null === $this->values) {
  162.             $this->initialize();
  163.         }
  164.         if ($fallbackKeys) {
  165.             $deleted $this->pool->deleteItems($fallbackKeys) && $deleted;
  166.         }
  167.         return $deleted;
  168.     }
  169.     /**
  170.      * {@inheritdoc}
  171.      */
  172.     public function save(CacheItemInterface $item)
  173.     {
  174.         if (null === $this->values) {
  175.             $this->initialize();
  176.         }
  177.         return !isset($this->values[$item->getKey()]) && $this->pool->save($item);
  178.     }
  179.     /**
  180.      * {@inheritdoc}
  181.      */
  182.     public function saveDeferred(CacheItemInterface $item)
  183.     {
  184.         if (null === $this->values) {
  185.             $this->initialize();
  186.         }
  187.         return !isset($this->values[$item->getKey()]) && $this->pool->saveDeferred($item);
  188.     }
  189.     /**
  190.      * {@inheritdoc}
  191.      */
  192.     public function commit()
  193.     {
  194.         return $this->pool->commit();
  195.     }
  196.     /**
  197.      * @return \Generator
  198.      */
  199.     private function generateItems(array $keys)
  200.     {
  201.         $f $this->createCacheItem;
  202.         $fallbackKeys = [];
  203.         foreach ($keys as $key) {
  204.             if (isset($this->values[$key])) {
  205.                 $value $this->values[$key];
  206.                 if ('N;' === $value) {
  207.                     yield $key => $f($keynulltrue);
  208.                 } elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
  209.                     try {
  210.                         yield $key => $f($keyunserialize($value), true);
  211.                     } catch (\Error $e) {
  212.                         yield $key => $f($keynullfalse);
  213.                     } catch (\Exception $e) {
  214.                         yield $key => $f($keynullfalse);
  215.                     }
  216.                 } else {
  217.                     yield $key => $f($key$valuetrue);
  218.                 }
  219.             } else {
  220.                 $fallbackKeys[] = $key;
  221.             }
  222.         }
  223.         if ($fallbackKeys) {
  224.             foreach ($this->pool->getItems($fallbackKeys) as $key => $item) {
  225.                 yield $key => $item;
  226.             }
  227.         }
  228.     }
  229.     /**
  230.      * @throws \ReflectionException When $class is not found and is required
  231.      *
  232.      * @internal to be removed in Symfony 5.0
  233.      */
  234.     public static function throwOnRequiredClass($class)
  235.     {
  236.         $e = new \ReflectionException("Class $class does not exist");
  237.         $trace debug_backtrace();
  238.         $autoloadFrame = [
  239.             'function' => 'spl_autoload_call',
  240.             'args' => [$class],
  241.         ];
  242.         if (\PHP_VERSION_ID >= 80000 && isset($trace[1])) {
  243.             $callerFrame $trace[1];
  244.         } elseif (false !== $i array_search($autoloadFrame$tracetrue)) {
  245.             $callerFrame $trace[++$i];
  246.         } else {
  247.             throw $e;
  248.         }
  249.         if (isset($callerFrame['function']) && !isset($callerFrame['class'])) {
  250.             switch ($callerFrame['function']) {
  251.                 case 'get_class_methods':
  252.                 case 'get_class_vars':
  253.                 case 'get_parent_class':
  254.                 case 'is_a':
  255.                 case 'is_subclass_of':
  256.                 case 'class_exists':
  257.                 case 'class_implements':
  258.                 case 'class_parents':
  259.                 case 'trait_exists':
  260.                 case 'defined':
  261.                 case 'interface_exists':
  262.                 case 'method_exists':
  263.                 case 'property_exists':
  264.                 case 'is_callable':
  265.                     return;
  266.             }
  267.         }
  268.         throw $e;
  269.     }
  270. }