vendor/doctrine/annotations/lib/Doctrine/Common/Annotations/CachedReader.php line 175

Open in your IDE?
  1. <?php
  2. namespace Doctrine\Common\Annotations;
  3. use Doctrine\Common\Cache\Cache;
  4. use ReflectionClass;
  5. use ReflectionMethod;
  6. use ReflectionProperty;
  7. use function array_map;
  8. use function array_merge;
  9. use function assert;
  10. use function filemtime;
  11. use function max;
  12. use function time;
  13. /**
  14.  * A cache aware annotation reader.
  15.  *
  16.  * @deprecated the CachedReader is deprecated and will be removed
  17.  *             in version 2.0.0 of doctrine/annotations. Please use the
  18.  *             {@see \Doctrine\Common\Annotations\PsrCachedReader} instead.
  19.  */
  20. final class CachedReader implements Reader
  21. {
  22.     /** @var Reader */
  23.     private $delegate;
  24.     /** @var Cache */
  25.     private $cache;
  26.     /** @var bool */
  27.     private $debug;
  28.     /** @var array<string, array<object>> */
  29.     private $loadedAnnotations = [];
  30.     /** @var int[] */
  31.     private $loadedFilemtimes = [];
  32.     /**
  33.      * @param bool $debug
  34.      */
  35.     public function __construct(Reader $readerCache $cache$debug false)
  36.     {
  37.         $this->delegate $reader;
  38.         $this->cache    $cache;
  39.         $this->debug    = (bool) $debug;
  40.     }
  41.     /**
  42.      * {@inheritDoc}
  43.      */
  44.     public function getClassAnnotations(ReflectionClass $class)
  45.     {
  46.         $cacheKey $class->getName();
  47.         if (isset($this->loadedAnnotations[$cacheKey])) {
  48.             return $this->loadedAnnotations[$cacheKey];
  49.         }
  50.         $annots $this->fetchFromCache($cacheKey$class);
  51.         if ($annots === false) {
  52.             $annots $this->delegate->getClassAnnotations($class);
  53.             $this->saveToCache($cacheKey$annots);
  54.         }
  55.         return $this->loadedAnnotations[$cacheKey] = $annots;
  56.     }
  57.     /**
  58.      * {@inheritDoc}
  59.      */
  60.     public function getClassAnnotation(ReflectionClass $class$annotationName)
  61.     {
  62.         foreach ($this->getClassAnnotations($class) as $annot) {
  63.             if ($annot instanceof $annotationName) {
  64.                 return $annot;
  65.             }
  66.         }
  67.         return null;
  68.     }
  69.     /**
  70.      * {@inheritDoc}
  71.      */
  72.     public function getPropertyAnnotations(ReflectionProperty $property)
  73.     {
  74.         $class    $property->getDeclaringClass();
  75.         $cacheKey $class->getName() . '$' $property->getName();
  76.         if (isset($this->loadedAnnotations[$cacheKey])) {
  77.             return $this->loadedAnnotations[$cacheKey];
  78.         }
  79.         $annots $this->fetchFromCache($cacheKey$class);
  80.         if ($annots === false) {
  81.             $annots $this->delegate->getPropertyAnnotations($property);
  82.             $this->saveToCache($cacheKey$annots);
  83.         }
  84.         return $this->loadedAnnotations[$cacheKey] = $annots;
  85.     }
  86.     /**
  87.      * {@inheritDoc}
  88.      */
  89.     public function getPropertyAnnotation(ReflectionProperty $property$annotationName)
  90.     {
  91.         foreach ($this->getPropertyAnnotations($property) as $annot) {
  92.             if ($annot instanceof $annotationName) {
  93.                 return $annot;
  94.             }
  95.         }
  96.         return null;
  97.     }
  98.     /**
  99.      * {@inheritDoc}
  100.      */
  101.     public function getMethodAnnotations(ReflectionMethod $method)
  102.     {
  103.         $class    $method->getDeclaringClass();
  104.         $cacheKey $class->getName() . '#' $method->getName();
  105.         if (isset($this->loadedAnnotations[$cacheKey])) {
  106.             return $this->loadedAnnotations[$cacheKey];
  107.         }
  108.         $annots $this->fetchFromCache($cacheKey$class);
  109.         if ($annots === false) {
  110.             $annots $this->delegate->getMethodAnnotations($method);
  111.             $this->saveToCache($cacheKey$annots);
  112.         }
  113.         return $this->loadedAnnotations[$cacheKey] = $annots;
  114.     }
  115.     /**
  116.      * {@inheritDoc}
  117.      */
  118.     public function getMethodAnnotation(ReflectionMethod $method$annotationName)
  119.     {
  120.         foreach ($this->getMethodAnnotations($method) as $annot) {
  121.             if ($annot instanceof $annotationName) {
  122.                 return $annot;
  123.             }
  124.         }
  125.         return null;
  126.     }
  127.     /**
  128.      * Clears loaded annotations.
  129.      *
  130.      * @return void
  131.      */
  132.     public function clearLoadedAnnotations()
  133.     {
  134.         $this->loadedAnnotations = [];
  135.         $this->loadedFilemtimes  = [];
  136.     }
  137.     /**
  138.      * Fetches a value from the cache.
  139.      *
  140.      * @param string $cacheKey The cache key.
  141.      *
  142.      * @return mixed The cached value or false when the value is not in cache.
  143.      */
  144.     private function fetchFromCache($cacheKeyReflectionClass $class)
  145.     {
  146.         $data $this->cache->fetch($cacheKey);
  147.         if ($data !== false) {
  148.             if (! $this->debug || $this->isCacheFresh($cacheKey$class)) {
  149.                 return $data;
  150.             }
  151.         }
  152.         return false;
  153.     }
  154.     /**
  155.      * Saves a value to the cache.
  156.      *
  157.      * @param string $cacheKey The cache key.
  158.      * @param mixed  $value    The value.
  159.      *
  160.      * @return void
  161.      */
  162.     private function saveToCache($cacheKey$value)
  163.     {
  164.         $this->cache->save($cacheKey$value);
  165.         if (! $this->debug) {
  166.             return;
  167.         }
  168.         $this->cache->save('[C]' $cacheKeytime());
  169.     }
  170.     /**
  171.      * Checks if the cache is fresh.
  172.      *
  173.      * @param string $cacheKey
  174.      *
  175.      * @return bool
  176.      */
  177.     private function isCacheFresh($cacheKeyReflectionClass $class)
  178.     {
  179.         $lastModification $this->getLastModification($class);
  180.         if ($lastModification === 0) {
  181.             return true;
  182.         }
  183.         return $this->cache->fetch('[C]' $cacheKey) >= $lastModification;
  184.     }
  185.     /**
  186.      * Returns the time the class was last modified, testing traits and parents
  187.      */
  188.     private function getLastModification(ReflectionClass $class): int
  189.     {
  190.         $filename $class->getFileName();
  191.         if (isset($this->loadedFilemtimes[$filename])) {
  192.             return $this->loadedFilemtimes[$filename];
  193.         }
  194.         $parent $class->getParentClass();
  195.         $lastModification =  max(array_merge(
  196.             [$filename filemtime($filename) : 0],
  197.             array_map(function (ReflectionClass $reflectionTrait): int {
  198.                 return $this->getTraitLastModificationTime($reflectionTrait);
  199.             }, $class->getTraits()),
  200.             array_map(function (ReflectionClass $class): int {
  201.                 return $this->getLastModification($class);
  202.             }, $class->getInterfaces()),
  203.             $parent ? [$this->getLastModification($parent)] : []
  204.         ));
  205.         assert($lastModification !== false);
  206.         return $this->loadedFilemtimes[$filename] = $lastModification;
  207.     }
  208.     private function getTraitLastModificationTime(ReflectionClass $reflectionTrait): int
  209.     {
  210.         $fileName $reflectionTrait->getFileName();
  211.         if (isset($this->loadedFilemtimes[$fileName])) {
  212.             return $this->loadedFilemtimes[$fileName];
  213.         }
  214.         $lastModificationTime max(array_merge(
  215.             [$fileName filemtime($fileName) : 0],
  216.             array_map(function (ReflectionClass $reflectionTrait): int {
  217.                 return $this->getTraitLastModificationTime($reflectionTrait);
  218.             }, $reflectionTrait->getTraits())
  219.         ));
  220.         assert($lastModificationTime !== false);
  221.         return $this->loadedFilemtimes[$fileName] = $lastModificationTime;
  222.     }
  223. }