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

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