vendor/symfony/cache/Adapter/PhpArrayAdapter.php line 113

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\ContractsTrait;
  18. use Symfony\Component\Cache\Traits\PhpArrayTrait;
  19. use Symfony\Contracts\Cache\CacheInterface;
  20. /**
  21.  * Caches items at warm up time using a PHP array that is stored in shared memory by OPCache since PHP 7.0.
  22.  * Warmed up items are read-only and run-time discovered items are cached using a fallback adapter.
  23.  *
  24.  * @author Titouan Galopin <galopintitouan@gmail.com>
  25.  * @author Nicolas Grekas <p@tchwork.com>
  26.  */
  27. class PhpArrayAdapter implements AdapterInterfaceCacheInterfacePruneableInterfaceResettableInterface
  28. {
  29.     use ContractsTrait;
  30.     use PhpArrayTrait;
  31.     private $createCacheItem;
  32.     /**
  33.      * @param string           $file         The PHP file were values are cached
  34.      * @param AdapterInterface $fallbackPool A pool to fallback on when an item is not hit
  35.      */
  36.     public function __construct(string $fileAdapterInterface $fallbackPool)
  37.     {
  38.         $this->file $file;
  39.         $this->pool $fallbackPool;
  40.         $this->createCacheItem = \Closure::bind(
  41.             static function ($key$value$isHit) {
  42.                 $item = new CacheItem();
  43.                 $item->key $key;
  44.                 $item->value $value;
  45.                 $item->isHit $isHit;
  46.                 return $item;
  47.             },
  48.             null,
  49.             CacheItem::class
  50.         );
  51.     }
  52.     /**
  53.      * This adapter takes advantage of how PHP stores arrays in its latest versions.
  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 (!$fallbackPool instanceof AdapterInterface) {
  63.             $fallbackPool = new ProxyAdapter($fallbackPool);
  64.         }
  65.         return new static($file$fallbackPool);
  66.     }
  67.     /**
  68.      * {@inheritdoc}
  69.      */
  70.     public function get(string $key, callable $callbackfloat $beta null, array &$metadata null)
  71.     {
  72.         if (null === $this->values) {
  73.             $this->initialize();
  74.         }
  75.         if (!isset($this->keys[$key])) {
  76.             get_from_pool:
  77.             if ($this->pool instanceof CacheInterface) {
  78.                 return $this->pool->get($key$callback$beta$metadata);
  79.             }
  80.             return $this->doGet($this->pool$key$callback$beta$metadata);
  81.         }
  82.         $value $this->values[$this->keys[$key]];
  83.         if ('N;' === $value) {
  84.             return null;
  85.         }
  86.         try {
  87.             if ($value instanceof \Closure) {
  88.                 return $value();
  89.             }
  90.         } catch (\Throwable $e) {
  91.             unset($this->keys[$key]);
  92.             goto get_from_pool;
  93.         }
  94.         return $value;
  95.     }
  96.     /**
  97.      * {@inheritdoc}
  98.      */
  99.     public function getItem($key)
  100.     {
  101.         if (!\is_string($key)) {
  102.             throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
  103.         }
  104.         if (null === $this->values) {
  105.             $this->initialize();
  106.         }
  107.         if (!isset($this->keys[$key])) {
  108.             return $this->pool->getItem($key);
  109.         }
  110.         $value $this->values[$this->keys[$key]];
  111.         $isHit true;
  112.         if ('N;' === $value) {
  113.             $value null;
  114.         } elseif ($value instanceof \Closure) {
  115.             try {
  116.                 $value $value();
  117.             } catch (\Throwable $e) {
  118.                 $value null;
  119.                 $isHit false;
  120.             }
  121.         }
  122.         $f $this->createCacheItem;
  123.         return $f($key$value$isHit);
  124.     }
  125.     /**
  126.      * {@inheritdoc}
  127.      */
  128.     public function getItems(array $keys = [])
  129.     {
  130.         foreach ($keys as $key) {
  131.             if (!\is_string($key)) {
  132.                 throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
  133.             }
  134.         }
  135.         if (null === $this->values) {
  136.             $this->initialize();
  137.         }
  138.         return $this->generateItems($keys);
  139.     }
  140.     /**
  141.      * {@inheritdoc}
  142.      *
  143.      * @return bool
  144.      */
  145.     public function hasItem($key)
  146.     {
  147.         if (!\is_string($key)) {
  148.             throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
  149.         }
  150.         if (null === $this->values) {
  151.             $this->initialize();
  152.         }
  153.         return isset($this->keys[$key]) || $this->pool->hasItem($key);
  154.     }
  155.     /**
  156.      * {@inheritdoc}
  157.      *
  158.      * @return bool
  159.      */
  160.     public function deleteItem($key)
  161.     {
  162.         if (!\is_string($key)) {
  163.             throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
  164.         }
  165.         if (null === $this->values) {
  166.             $this->initialize();
  167.         }
  168.         return !isset($this->keys[$key]) && $this->pool->deleteItem($key);
  169.     }
  170.     /**
  171.      * {@inheritdoc}
  172.      *
  173.      * @return bool
  174.      */
  175.     public function deleteItems(array $keys)
  176.     {
  177.         $deleted true;
  178.         $fallbackKeys = [];
  179.         foreach ($keys as $key) {
  180.             if (!\is_string($key)) {
  181.                 throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
  182.             }
  183.             if (isset($this->keys[$key])) {
  184.                 $deleted false;
  185.             } else {
  186.                 $fallbackKeys[] = $key;
  187.             }
  188.         }
  189.         if (null === $this->values) {
  190.             $this->initialize();
  191.         }
  192.         if ($fallbackKeys) {
  193.             $deleted $this->pool->deleteItems($fallbackKeys) && $deleted;
  194.         }
  195.         return $deleted;
  196.     }
  197.     /**
  198.      * {@inheritdoc}
  199.      *
  200.      * @return bool
  201.      */
  202.     public function save(CacheItemInterface $item)
  203.     {
  204.         if (null === $this->values) {
  205.             $this->initialize();
  206.         }
  207.         return !isset($this->keys[$item->getKey()]) && $this->pool->save($item);
  208.     }
  209.     /**
  210.      * {@inheritdoc}
  211.      *
  212.      * @return bool
  213.      */
  214.     public function saveDeferred(CacheItemInterface $item)
  215.     {
  216.         if (null === $this->values) {
  217.             $this->initialize();
  218.         }
  219.         return !isset($this->keys[$item->getKey()]) && $this->pool->saveDeferred($item);
  220.     }
  221.     /**
  222.      * {@inheritdoc}
  223.      *
  224.      * @return bool
  225.      */
  226.     public function commit()
  227.     {
  228.         return $this->pool->commit();
  229.     }
  230.     private function generateItems(array $keys): \Generator
  231.     {
  232.         $f $this->createCacheItem;
  233.         $fallbackKeys = [];
  234.         foreach ($keys as $key) {
  235.             if (isset($this->keys[$key])) {
  236.                 $value $this->values[$this->keys[$key]];
  237.                 if ('N;' === $value) {
  238.                     yield $key => $f($keynulltrue);
  239.                 } elseif ($value instanceof \Closure) {
  240.                     try {
  241.                         yield $key => $f($key$value(), true);
  242.                     } catch (\Throwable $e) {
  243.                         yield $key => $f($keynullfalse);
  244.                     }
  245.                 } else {
  246.                     yield $key => $f($key$valuetrue);
  247.                 }
  248.             } else {
  249.                 $fallbackKeys[] = $key;
  250.             }
  251.         }
  252.         if ($fallbackKeys) {
  253.             yield from $this->pool->getItems($fallbackKeys);
  254.         }
  255.     }
  256.     /**
  257.      * @throws \ReflectionException When $class is not found and is required
  258.      *
  259.      * @internal to be removed in Symfony 5.0
  260.      */
  261.     public static function throwOnRequiredClass($class)
  262.     {
  263.         $e = new \ReflectionException("Class $class does not exist");
  264.         $trace debug_backtrace();
  265.         $autoloadFrame = [
  266.             'function' => 'spl_autoload_call',
  267.             'args' => [$class],
  268.         ];
  269.         if (\PHP_VERSION_ID >= 80000 && isset($trace[1])) {
  270.             $callerFrame $trace[1];
  271.         } elseif (false !== $i array_search($autoloadFrame$tracetrue)) {
  272.             $callerFrame $trace[++$i];
  273.         } else {
  274.             throw $e;
  275.         }
  276.         if (isset($callerFrame['function']) && !isset($callerFrame['class'])) {
  277.             switch ($callerFrame['function']) {
  278.                 case 'get_class_methods':
  279.                 case 'get_class_vars':
  280.                 case 'get_parent_class':
  281.                 case 'is_a':
  282.                 case 'is_subclass_of':
  283.                 case 'class_exists':
  284.                 case 'class_implements':
  285.                 case 'class_parents':
  286.                 case 'trait_exists':
  287.                 case 'defined':
  288.                 case 'interface_exists':
  289.                 case 'method_exists':
  290.                 case 'property_exists':
  291.                 case 'is_callable':
  292.                     return;
  293.             }
  294.         }
  295.         throw $e;
  296.     }
  297. }