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

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 PhpArrayTrait;
  30.     use ContractsTrait;
  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.             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 Fallback when opcache is disabled
  57.      *
  58.      * @return CacheItemPoolInterface
  59.      */
  60.     public static function create($fileCacheItemPoolInterface $fallbackPool)
  61.     {
  62.         // Shared memory is available in PHP 7.0+ with OPCache enabled
  63.         if (filter_var(ini_get('opcache.enable'), FILTER_VALIDATE_BOOLEAN)) {
  64.             if (!$fallbackPool instanceof AdapterInterface) {
  65.                 $fallbackPool = new ProxyAdapter($fallbackPool);
  66.             }
  67.             return new static($file$fallbackPool);
  68.         }
  69.         return $fallbackPool;
  70.     }
  71.     /**
  72.      * {@inheritdoc}
  73.      */
  74.     public function get(string $key, callable $callbackfloat $beta null, array &$metadata null)
  75.     {
  76.         if (null === $this->values) {
  77.             $this->initialize();
  78.         }
  79.         if (!isset($this->keys[$key])) {
  80.             get_from_pool:
  81.             if ($this->pool instanceof CacheInterface) {
  82.                 return $this->pool->get($key$callback$beta$metadata);
  83.             }
  84.             return $this->doGet($this->pool$key$callback$beta$metadata);
  85.         }
  86.         $value $this->values[$this->keys[$key]];
  87.         if ('N;' === $value) {
  88.             return null;
  89.         }
  90.         try {
  91.             if ($value instanceof \Closure) {
  92.                 return $value();
  93.             }
  94.         } catch (\Throwable $e) {
  95.             unset($this->keys[$key]);
  96.             goto get_from_pool;
  97.         }
  98.         return $value;
  99.     }
  100.     /**
  101.      * {@inheritdoc}
  102.      */
  103.     public function getItem($key)
  104.     {
  105.         if (!\is_string($key)) {
  106.             throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
  107.         }
  108.         if (null === $this->values) {
  109.             $this->initialize();
  110.         }
  111.         if (!isset($this->keys[$key])) {
  112.             return $this->pool->getItem($key);
  113.         }
  114.         $value $this->values[$this->keys[$key]];
  115.         $isHit true;
  116.         if ('N;' === $value) {
  117.             $value null;
  118.         } elseif ($value instanceof \Closure) {
  119.             try {
  120.                 $value $value();
  121.             } catch (\Throwable $e) {
  122.                 $value null;
  123.                 $isHit false;
  124.             }
  125.         }
  126.         $f $this->createCacheItem;
  127.         return $f($key$value$isHit);
  128.     }
  129.     /**
  130.      * {@inheritdoc}
  131.      */
  132.     public function getItems(array $keys = [])
  133.     {
  134.         foreach ($keys as $key) {
  135.             if (!\is_string($key)) {
  136.                 throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
  137.             }
  138.         }
  139.         if (null === $this->values) {
  140.             $this->initialize();
  141.         }
  142.         return $this->generateItems($keys);
  143.     }
  144.     /**
  145.      * {@inheritdoc}
  146.      */
  147.     public function hasItem($key)
  148.     {
  149.         if (!\is_string($key)) {
  150.             throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
  151.         }
  152.         if (null === $this->values) {
  153.             $this->initialize();
  154.         }
  155.         return isset($this->keys[$key]) || $this->pool->hasItem($key);
  156.     }
  157.     /**
  158.      * {@inheritdoc}
  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.     public function deleteItems(array $keys)
  174.     {
  175.         $deleted true;
  176.         $fallbackKeys = [];
  177.         foreach ($keys as $key) {
  178.             if (!\is_string($key)) {
  179.                 throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
  180.             }
  181.             if (isset($this->keys[$key])) {
  182.                 $deleted false;
  183.             } else {
  184.                 $fallbackKeys[] = $key;
  185.             }
  186.         }
  187.         if (null === $this->values) {
  188.             $this->initialize();
  189.         }
  190.         if ($fallbackKeys) {
  191.             $deleted $this->pool->deleteItems($fallbackKeys) && $deleted;
  192.         }
  193.         return $deleted;
  194.     }
  195.     /**
  196.      * {@inheritdoc}
  197.      */
  198.     public function save(CacheItemInterface $item)
  199.     {
  200.         if (null === $this->values) {
  201.             $this->initialize();
  202.         }
  203.         return !isset($this->keys[$item->getKey()]) && $this->pool->save($item);
  204.     }
  205.     /**
  206.      * {@inheritdoc}
  207.      */
  208.     public function saveDeferred(CacheItemInterface $item)
  209.     {
  210.         if (null === $this->values) {
  211.             $this->initialize();
  212.         }
  213.         return !isset($this->keys[$item->getKey()]) && $this->pool->saveDeferred($item);
  214.     }
  215.     /**
  216.      * {@inheritdoc}
  217.      */
  218.     public function commit()
  219.     {
  220.         return $this->pool->commit();
  221.     }
  222.     private function generateItems(array $keys): \Generator
  223.     {
  224.         $f $this->createCacheItem;
  225.         $fallbackKeys = [];
  226.         foreach ($keys as $key) {
  227.             if (isset($this->keys[$key])) {
  228.                 $value $this->values[$this->keys[$key]];
  229.                 if ('N;' === $value) {
  230.                     yield $key => $f($keynulltrue);
  231.                 } elseif ($value instanceof \Closure) {
  232.                     try {
  233.                         yield $key => $f($key$value(), true);
  234.                     } catch (\Throwable $e) {
  235.                         yield $key => $f($keynullfalse);
  236.                     }
  237.                 } else {
  238.                     yield $key => $f($key$valuetrue);
  239.                 }
  240.             } else {
  241.                 $fallbackKeys[] = $key;
  242.             }
  243.         }
  244.         if ($fallbackKeys) {
  245.             yield from $this->pool->getItems($fallbackKeys);
  246.         }
  247.     }
  248.     /**
  249.      * @throws \ReflectionException When $class is not found and is required
  250.      *
  251.      * @internal
  252.      */
  253.     public static function throwOnRequiredClass($class)
  254.     {
  255.         $e = new \ReflectionException("Class $class does not exist");
  256.         $trace $e->getTrace();
  257.         $autoloadFrame = [
  258.             'function' => 'spl_autoload_call',
  259.             'args' => [$class],
  260.         ];
  261.         $i array_search($autoloadFrame$tracetrue);
  262.         if (isset($trace[$i]['function']) && !isset($trace[$i]['class'])) {
  263.             switch ($trace[$i]['function']) {
  264.                 case 'get_class_methods':
  265.                 case 'get_class_vars':
  266.                 case 'get_parent_class':
  267.                 case 'is_a':
  268.                 case 'is_subclass_of':
  269.                 case 'class_exists':
  270.                 case 'class_implements':
  271.                 case 'class_parents':
  272.                 case 'trait_exists':
  273.                 case 'defined':
  274.                 case 'interface_exists':
  275.                 case 'method_exists':
  276.                 case 'property_exists':
  277.                 case 'is_callable':
  278.                     return;
  279.             }
  280.         }
  281.         throw $e;
  282.     }
  283. }