PsrCachedReader.php
Namespace
Doctrine\Common\AnnotationsFile
-
vendor/
doctrine/ annotations/ lib/ Doctrine/ Common/ Annotations/ PsrCachedReader.php
View source
<?php
namespace Doctrine\Common\Annotations;
use Psr\Cache\CacheItemPoolInterface;
use ReflectionClass;
use ReflectionMethod;
use ReflectionProperty;
use Reflector;
use function array_map;
use function array_merge;
use function assert;
use function filemtime;
use function is_file;
use function max;
use function rawurlencode;
use function time;
/**
* A cache aware annotation reader.
*/
final class PsrCachedReader implements Reader {
/** @var Reader */
private $delegate;
/** @var CacheItemPoolInterface */
private $cache;
/** @var bool */
private $debug;
/** @var array<string, array<object>> */
private $loadedAnnotations = [];
/** @var int[] */
private $loadedFilemtimes = [];
public function __construct(Reader $reader, CacheItemPoolInterface $cache, bool $debug = false) {
$this->delegate = $reader;
$this->cache = $cache;
$this->debug = (bool) $debug;
}
/**
* {@inheritDoc}
*/
public function getClassAnnotations(ReflectionClass $class) {
$cacheKey = $class->getName();
if (isset($this->loadedAnnotations[$cacheKey])) {
return $this->loadedAnnotations[$cacheKey];
}
$annots = $this->fetchFromCache($cacheKey, $class, 'getClassAnnotations', $class);
return $this->loadedAnnotations[$cacheKey] = $annots;
}
/**
* {@inheritDoc}
*/
public function getClassAnnotation(ReflectionClass $class, $annotationName) {
foreach ($this->getClassAnnotations($class) as $annot) {
if ($annot instanceof $annotationName) {
return $annot;
}
}
return null;
}
/**
* {@inheritDoc}
*/
public function getPropertyAnnotations(ReflectionProperty $property) {
$class = $property->getDeclaringClass();
$cacheKey = $class->getName() . '$' . $property->getName();
if (isset($this->loadedAnnotations[$cacheKey])) {
return $this->loadedAnnotations[$cacheKey];
}
$annots = $this->fetchFromCache($cacheKey, $class, 'getPropertyAnnotations', $property);
return $this->loadedAnnotations[$cacheKey] = $annots;
}
/**
* {@inheritDoc}
*/
public function getPropertyAnnotation(ReflectionProperty $property, $annotationName) {
foreach ($this->getPropertyAnnotations($property) as $annot) {
if ($annot instanceof $annotationName) {
return $annot;
}
}
return null;
}
/**
* {@inheritDoc}
*/
public function getMethodAnnotations(ReflectionMethod $method) {
$class = $method->getDeclaringClass();
$cacheKey = $class->getName() . '#' . $method->getName();
if (isset($this->loadedAnnotations[$cacheKey])) {
return $this->loadedAnnotations[$cacheKey];
}
$annots = $this->fetchFromCache($cacheKey, $class, 'getMethodAnnotations', $method);
return $this->loadedAnnotations[$cacheKey] = $annots;
}
/**
* {@inheritDoc}
*/
public function getMethodAnnotation(ReflectionMethod $method, $annotationName) {
foreach ($this->getMethodAnnotations($method) as $annot) {
if ($annot instanceof $annotationName) {
return $annot;
}
}
return null;
}
public function clearLoadedAnnotations() : void {
$this->loadedAnnotations = [];
$this->loadedFilemtimes = [];
}
/** @return mixed[] */
private function fetchFromCache(string $cacheKey, ReflectionClass $class, string $method, Reflector $reflector) : array {
$cacheKey = rawurlencode($cacheKey);
$item = $this->cache
->getItem($cacheKey);
if ($this->debug && !$this->refresh($cacheKey, $class) || !$item->isHit()) {
$this->cache
->save($item->set($this->delegate
->{$method}($reflector)));
}
return $item->get();
}
/**
* Used in debug mode to check if the cache is fresh.
*
* @return bool Returns true if the cache was fresh, or false if the class
* being read was modified since writing to the cache.
*/
private function refresh(string $cacheKey, ReflectionClass $class) : bool {
$lastModification = $this->getLastModification($class);
if ($lastModification === 0) {
return true;
}
$item = $this->cache
->getItem('[C]' . $cacheKey);
if ($item->isHit() && $item->get() >= $lastModification) {
return true;
}
$this->cache
->save($item->set(time()));
return false;
}
/**
* Returns the time the class was last modified, testing traits and parents
*/
private function getLastModification(ReflectionClass $class) : int {
$filename = $class->getFileName();
if (isset($this->loadedFilemtimes[$filename])) {
return $this->loadedFilemtimes[$filename];
}
$parent = $class->getParentClass();
$lastModification = max(array_merge([
$filename !== false && is_file($filename) ? filemtime($filename) : 0,
], array_map(function (ReflectionClass $reflectionTrait) : int {
return $this->getTraitLastModificationTime($reflectionTrait);
}, $class->getTraits()), array_map(function (ReflectionClass $class) : int {
return $this->getLastModification($class);
}, $class->getInterfaces()), $parent ? [
$this->getLastModification($parent),
] : []));
assert($lastModification !== false);
return $this->loadedFilemtimes[$filename] = $lastModification;
}
private function getTraitLastModificationTime(ReflectionClass $reflectionTrait) : int {
$fileName = $reflectionTrait->getFileName();
if (isset($this->loadedFilemtimes[$fileName])) {
return $this->loadedFilemtimes[$fileName];
}
$lastModificationTime = max(array_merge([
$fileName !== false && is_file($fileName) ? filemtime($fileName) : 0,
], array_map(function (ReflectionClass $reflectionTrait) : int {
return $this->getTraitLastModificationTime($reflectionTrait);
}, $reflectionTrait->getTraits())));
assert($lastModificationTime !== false);
return $this->loadedFilemtimes[$fileName] = $lastModificationTime;
}
}
Classes
Title | Deprecated | Summary |
---|---|---|
PsrCachedReader | A cache aware annotation reader. |