namespace Doctrine\Common\Annotations;
use Doctrine\Common\Cache\Cache;
+use ReflectionClass;
/**
* A cache aware annotation reader.
*/
final class CachedReader implements Reader
{
- /**
- * @var string
- */
- private static $CACHE_SALT = '@[Annot]';
-
/**
* @var Reader
*/
/**
* {@inheritDoc}
*/
- public function getClassAnnotations(\ReflectionClass $class)
+ public function getClassAnnotations(ReflectionClass $class)
{
$cacheKey = $class->getName();
/**
* {@inheritDoc}
*/
- public function getClassAnnotation(\ReflectionClass $class, $annotationName)
+ public function getClassAnnotation(ReflectionClass $class, $annotationName)
{
foreach ($this->getClassAnnotations($class) as $annot) {
if ($annot instanceof $annotationName) {
/**
* Fetches a value from the cache.
*
- * @param string $rawCacheKey The cache key.
- * @param \ReflectionClass $class The related class.
+ * @param string $cacheKey The cache key.
+ * @param ReflectionClass $class The related class.
*
* @return mixed The cached value or false when the value is not in cache.
*/
- private function fetchFromCache($rawCacheKey, \ReflectionClass $class)
+ private function fetchFromCache($cacheKey, ReflectionClass $class)
{
- $cacheKey = $rawCacheKey . self::$CACHE_SALT;
if (($data = $this->cache->fetch($cacheKey)) !== false) {
if (!$this->debug || $this->isCacheFresh($cacheKey, $class)) {
return $data;
/**
* Saves a value to the cache.
*
- * @param string $rawCacheKey The cache key.
- * @param mixed $value The value.
+ * @param string $cacheKey The cache key.
+ * @param mixed $value The value.
*
* @return void
*/
- private function saveToCache($rawCacheKey, $value)
+ private function saveToCache($cacheKey, $value)
{
- $cacheKey = $rawCacheKey . self::$CACHE_SALT;
$this->cache->save($cacheKey, $value);
if ($this->debug) {
$this->cache->save('[C]'.$cacheKey, time());
* Checks if the cache is fresh.
*
* @param string $cacheKey
- * @param \ReflectionClass $class
+ * @param ReflectionClass $class
*
* @return boolean
*/
- private function isCacheFresh($cacheKey, \ReflectionClass $class)
+ private function isCacheFresh($cacheKey, ReflectionClass $class)
{
- if (false === $filename = $class->getFilename()) {
+ if (null === $lastModification = $this->getLastModification($class)) {
return true;
}
- return $this->cache->fetch('[C]'.$cacheKey) >= filemtime($filename);
+ return $this->cache->fetch('[C]'.$cacheKey) >= $lastModification;
+ }
+
+ /**
+ * Returns the time the class was last modified, testing traits and parents
+ *
+ * @param ReflectionClass $class
+ * @return int
+ */
+ private function getLastModification(ReflectionClass $class)
+ {
+ $filename = $class->getFileName();
+ $parent = $class->getParentClass();
+
+ return max(array_merge(
+ [$filename ? filemtime($filename) : 0],
+ array_map([$this, 'getTraitLastModificationTime'], $class->getTraits()),
+ array_map([$this, 'getLastModification'], $class->getInterfaces()),
+ $parent ? [$this->getLastModification($parent)] : []
+ ));
+ }
+
+ /**
+ * @param ReflectionClass $reflectionTrait
+ * @return int
+ */
+ private function getTraitLastModificationTime(ReflectionClass $reflectionTrait)
+ {
+ $fileName = $reflectionTrait->getFileName();
+
+ return max(array_merge(
+ [$fileName ? filemtime($fileName) : 0],
+ array_map([$this, 'getTraitLastModificationTime'], $reflectionTrait->getTraits())
+ ));
}
}