[BUGFIX] Optimize cache handling in ReflectionService 80/50980/2
authorHelmut Hummel <typo3@helhum.io>
Tue, 13 Dec 2016 22:39:13 +0000 (23:39 +0100)
committerMarkus Klein <markus.klein@typo3.org>
Fri, 16 Dec 2016 00:18:07 +0000 (01:18 +0100)
Method reflection objects are used temporarily to extract information
from methods. This information is eventually stored in the cache.
However the method reflection objects themselves must stay outside the cache
because they cannot be serialized. They also do not provide much value
as the information is stored in the cache anyway.
The only additional info these reflections provided is whether a method
existed or not in the class, which we now also cache as plain array.

Furthermore the information whether cache relevant properties were
updated and the cache needs to be saved again is now reset once it was
written. This ensures that the cache is only written once even the
ReflectionService is used multiple times.

Resolves: #78915
Resolves: #78977
Releases: master, 7.6, 6.2
Change-Id: I1d00f596633adab886c0db0dfddd71358fb67303
Reviewed-on: https://review.typo3.org/50980
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Markus Klein <markus.klein@typo3.org>
Tested-by: Markus Klein <markus.klein@typo3.org>
typo3/sysext/extbase/Classes/Reflection/ReflectionService.php

index 947cfd7..f7185fc 100644 (file)
@@ -94,6 +94,13 @@ class ReflectionService implements \TYPO3\CMS\Core\SingletonInterface
     protected $classPropertyNames = [];
 
     /**
+     * Array of class names and names of their methods.
+     *
+     * @var array
+     */
+    protected $classMethodNames = [];
+
+    /**
      * Array of class names, property names and their tags and values.
      *
      * @var array
@@ -137,6 +144,8 @@ class ReflectionService implements \TYPO3\CMS\Core\SingletonInterface
     protected $cacheIdentifier;
 
     /**
+     * Internal runtime cache of method reflection objects
+     *
      * @var array
      */
     protected $methodReflections = [];
@@ -285,15 +294,15 @@ class ReflectionService implements \TYPO3\CMS\Core\SingletonInterface
     public function hasMethod($className, $methodName)
     {
         try {
-            if (!array_key_exists($className, $this->methodReflections) || !array_key_exists($methodName, $this->methodReflections[$className])) {
-                $this->methodReflections[$className][$methodName] = new MethodReflection($className, $methodName);
-                $this->dataCacheNeedsUpdate = true;
+            if (!array_key_exists($className, $this->classMethodNames) || !array_key_exists($methodName, $this->classMethodNames[$className])) {
+                $this->getMethodReflection($className, $methodName);
+                $this->classMethodNames[$className][$methodName] = true;
             }
         } catch (\ReflectionException $e) {
             // Method does not exist. Store this information in cache.
-            $this->methodReflections[$className][$methodName] = null;
+            $this->classMethodNames[$className][$methodName] = null;
         }
-        return isset($this->methodReflections[$className][$methodName]);
+        return isset($this->classMethodNames[$className][$methodName]);
     }
 
     /**
@@ -306,8 +315,8 @@ class ReflectionService implements \TYPO3\CMS\Core\SingletonInterface
     public function getMethodTagsValues($className, $methodName)
     {
         if (!isset($this->methodTagsValues[$className][$methodName])) {
-            $this->methodTagsValues[$className][$methodName] = [];
             $method = $this->getMethodReflection($className, $methodName);
+            $this->methodTagsValues[$className][$methodName] = [];
             foreach ($method->getTagsValues() as $tag => $values) {
                 if (array_search($tag, $this->ignoredTags) === false) {
                     $this->methodTagsValues[$className][$methodName][$tag] = $values;
@@ -563,9 +572,9 @@ class ReflectionService implements \TYPO3\CMS\Core\SingletonInterface
      */
     protected function getMethodReflection($className, $methodName)
     {
+        $this->dataCacheNeedsUpdate = true;
         if (!isset($this->methodReflections[$className][$methodName])) {
             $this->methodReflections[$className][$methodName] = new MethodReflection($className, $methodName);
-            $this->dataCacheNeedsUpdate = true;
         }
         return $this->methodReflections[$className][$methodName];
     }
@@ -600,6 +609,7 @@ class ReflectionService implements \TYPO3\CMS\Core\SingletonInterface
         $propertyNames = [
             'reflectedClassNames',
             'classPropertyNames',
+            'classMethodNames',
             'classTagsValues',
             'methodTagsValues',
             'methodParameters',
@@ -611,5 +621,6 @@ class ReflectionService implements \TYPO3\CMS\Core\SingletonInterface
             $data[$propertyName] = $this->{$propertyName};
         }
         $this->dataCache->set($this->cacheIdentifier, $data);
+        $this->dataCacheNeedsUpdate = false;
     }
 }