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

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 Fallback for old PHP versions or opcache 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 and in HHVM
  63.         if ((\PHP_VERSION_ID >= 70000 && filter_var(ini_get('opcache.enable'), FILTER_VALIDATE_BOOLEAN)) || \defined('HHVM_VERSION')) {
  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 getItem($key)
  75.     {
  76.         if (!\is_string($key)) {
  77.             throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
  78.         }
  79.         if (null === $this->values) {
  80.             $this->initialize();
  81.         }
  82.         if (!isset($this->values[$key])) {
  83.             return $this->pool->getItem($key);
  84.         }
  85.         $value $this->values[$key];
  86.         $isHit true;
  87.         if ('N;' === $value) {
  88.             $value null;
  89.         } elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
  90.             try {
  91.                 $e null;
  92.                 $value unserialize($value);
  93.             } catch (\Error $e) {
  94.             } catch (\Exception $e) {
  95.             }
  96.             if (null !== $e) {
  97.                 $value null;
  98.                 $isHit false;
  99.             }
  100.         }
  101.         $f $this->createCacheItem;
  102.         return $f($key$value$isHit);
  103.     }
  104.     /**
  105.      * {@inheritdoc}
  106.      */
  107.     public function getItems(array $keys = [])
  108.     {
  109.         foreach ($keys as $key) {
  110.             if (!\is_string($key)) {
  111.                 throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
  112.             }
  113.         }
  114.         if (null === $this->values) {
  115.             $this->initialize();
  116.         }
  117.         return $this->generateItems($keys);
  118.     }
  119.     /**
  120.      * {@inheritdoc}
  121.      */
  122.     public function hasItem($key)
  123.     {
  124.         if (!\is_string($key)) {
  125.             throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
  126.         }
  127.         if (null === $this->values) {
  128.             $this->initialize();
  129.         }
  130.         return isset($this->values[$key]) || $this->pool->hasItem($key);
  131.     }
  132.     /**
  133.      * {@inheritdoc}
  134.      */
  135.     public function deleteItem($key)
  136.     {
  137.         if (!\is_string($key)) {
  138.             throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
  139.         }
  140.         if (null === $this->values) {
  141.             $this->initialize();
  142.         }
  143.         return !isset($this->values[$key]) && $this->pool->deleteItem($key);
  144.     }
  145.     /**
  146.      * {@inheritdoc}
  147.      */
  148.     public function deleteItems(array $keys)
  149.     {
  150.         $deleted true;
  151.         $fallbackKeys = [];
  152.         foreach ($keys as $key) {
  153.             if (!\is_string($key)) {
  154.                 throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key)));
  155.             }
  156.             if (isset($this->values[$key])) {
  157.                 $deleted false;
  158.             } else {
  159.                 $fallbackKeys[] = $key;
  160.             }
  161.         }
  162.         if (null === $this->values) {
  163.             $this->initialize();
  164.         }
  165.         if ($fallbackKeys) {
  166.             $deleted $this->pool->deleteItems($fallbackKeys) && $deleted;
  167.         }
  168.         return $deleted;
  169.     }
  170.     /**
  171.      * {@inheritdoc}
  172.      */
  173.     public function save(CacheItemInterface $item)
  174.     {
  175.         if (null === $this->values) {
  176.             $this->initialize();
  177.         }
  178.         return !isset($this->values[$item->getKey()]) && $this->pool->save($item);
  179.     }
  180.     /**
  181.      * {@inheritdoc}
  182.      */
  183.     public function saveDeferred(CacheItemInterface $item)
  184.     {
  185.         if (null === $this->values) {
  186.             $this->initialize();
  187.         }
  188.         return !isset($this->values[$item->getKey()]) && $this->pool->saveDeferred($item);
  189.     }
  190.     /**
  191.      * {@inheritdoc}
  192.      */
  193.     public function commit()
  194.     {
  195.         return $this->pool->commit();
  196.     }
  197.     /**
  198.      * @return \Generator
  199.      */
  200.     private function generateItems(array $keys)
  201.     {
  202.         $f $this->createCacheItem;
  203.         $fallbackKeys = [];
  204.         foreach ($keys as $key) {
  205.             if (isset($this->values[$key])) {
  206.                 $value $this->values[$key];
  207.                 if ('N;' === $value) {
  208.                     yield $key => $f($keynulltrue);
  209.                 } elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
  210.                     try {
  211.                         yield $key => $f($keyunserialize($value), true);
  212.                     } catch (\Error $e) {
  213.                         yield $key => $f($keynullfalse);
  214.                     } catch (\Exception $e) {
  215.                         yield $key => $f($keynullfalse);
  216.                     }
  217.                 } else {
  218.                     yield $key => $f($key$valuetrue);
  219.                 }
  220.             } else {
  221.                 $fallbackKeys[] = $key;
  222.             }
  223.         }
  224.         if ($fallbackKeys) {
  225.             foreach ($this->pool->getItems($fallbackKeys) as $key => $item) {
  226.                 yield $key => $item;
  227.             }
  228.         }
  229.     }
  230.     /**
  231.      * @throws \ReflectionException When $class is not found and is required
  232.      *
  233.      * @internal to be removed in Symfony 5.0
  234.      */
  235.     public static function throwOnRequiredClass($class)
  236.     {
  237.         $e = new \ReflectionException("Class $class does not exist");
  238.         $trace $e->getTrace();
  239.         $autoloadFrame = [
  240.             'function' => 'spl_autoload_call',
  241.             'args' => [$class],
  242.         ];
  243.         $i array_search($autoloadFrame$tracetrue);
  244.         if (isset($trace[$i]['function']) && !isset($trace[$i]['class'])) {
  245.             switch ($trace[$i]['function']) {
  246.                 case 'get_class_methods':
  247.                 case 'get_class_vars':
  248.                 case 'get_parent_class':
  249.                 case 'is_a':
  250.                 case 'is_subclass_of':
  251.                 case 'class_exists':
  252.                 case 'class_implements':
  253.                 case 'class_parents':
  254.                 case 'trait_exists':
  255.                 case 'defined':
  256.                 case 'interface_exists':
  257.                 case 'method_exists':
  258.                 case 'property_exists':
  259.                 case 'is_callable':
  260.                     return;
  261.             }
  262.         }
  263.         throw $e;
  264.     }
  265. }