[TASK] Optimize speed for instantiating class with arguments 43/26643/2
authorHelmut Hummel <helmut.hummel@typo3.org>
Sat, 14 Dec 2013 22:35:02 +0000 (23:35 +0100)
committerStefan Neufeind <typo3.neufeind@speedpartner.de>
Fri, 17 Jan 2014 08:28:02 +0000 (09:28 +0100)
PHP reflection has quite an overhead in performance.
Use a switch construct like in Flow instead to
instantiate classes with up to 8 arguments without
reflection.

Resolves: #53682
Releases: 6.2, 6.1, 6.0, 4.7, 4.5
Change-Id: I82ecf0b1ea9a412a39b4429d7689f2bb6489f3df
Reviewed-on: https://review.typo3.org/26643
Reviewed-by: Markus Klein
Reviewed-by: Stefan Neufeind
Tested-by: Stefan Neufeind
t3lib/class.t3lib_div.php
typo3/sysext/cms/tslib/class.tslib_content.php

index b31ebe0..b6e1610 100644 (file)
@@ -5367,15 +5367,7 @@ final class t3lib_div {
                }
 
                        // Create new instance and call constructor with parameters
-               if (func_num_args() > 1) {
-                       $constructorArguments = func_get_args();
-                       array_shift($constructorArguments);
-
-                       $reflectedClass = new ReflectionClass($finalClassName);
-                       $instance = $reflectedClass->newInstanceArgs($constructorArguments);
-               } else {
-                       $instance = new $finalClassName;
-               }
+               $instance = static::instantiateClass($finalClassName, func_get_args());
 
                        // Register new singleton instance
                if ($instance instanceof t3lib_Singleton) {
@@ -5401,6 +5393,54 @@ final class t3lib_div {
        }
 
        /**
+        * Speed optimized alternative to ReflectionClass::newInstanceArgs()
+        *
+        * @param string $className Name of the class to instantiate
+        * @param array $arguments Arguments passed to self::makeInstance() thus the first one with index 0 holds the requested class name
+        * @return mixed
+        */
+       protected static function instantiateClass($className, $arguments) {
+               switch (count($arguments)) {
+                       case 1:
+                               $instance = new $className();
+                               break;
+                       case 2:
+                               $instance = new $className($arguments[1]);
+                               break;
+                       case 3:
+                               $instance = new $className($arguments[1], $arguments[2]);
+                               break;
+                       case 4:
+                               $instance = new $className($arguments[1], $arguments[2], $arguments[3]);
+                               break;
+                       case 5:
+                               $instance = new $className($arguments[1], $arguments[2], $arguments[3], $arguments[4]);
+                               break;
+                       case 6:
+                               $instance = new $className($arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5]);
+                               break;
+                       case 7:
+                               $instance = new $className($arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5], $arguments[6]);
+                               break;
+                       case 8:
+                               $instance = new $className($arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5], $arguments[6], $arguments[7]);
+                               break;
+                       case 9:
+                               $instance = new $className($arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5], $arguments[6], $arguments[7], $arguments[8]);
+                               break;
+                       default:
+                               // The default case for classes with constructors that have more than 8 arguments.
+                               // This will fail when one of the arguments shall be passed by reference.
+                               // In case we really need to support this edge case, we can implement the solution from here: https://review.typo3.org/26344
+                               $class = new ReflectionClass($className);
+                               array_shift($arguments);
+                               $instance = $class->newInstanceArgs($arguments);
+                               return $instance;
+               }
+               return $instance;
+       }
+
+       /**
         * Returns the class name for a new instance, taking into account the
         * class-extension API.
         *
index 166ced1..7e36ec3 100644 (file)
@@ -847,9 +847,10 @@ class tslib_cObj {
                $name = $classMapping[$name];
 
                if (!array_key_exists($name, $this->contentObjects)) {
-                       try {
-                               $this->contentObjects[$name] = t3lib_div::makeInstance('tslib_content_' . $name, $this);
-                       } catch (ReflectionException $e) {
+                       $fullyQualifiedClassName = 'tslib_content_' . $name;
+                       if (class_exists($fullyQualifiedClassName)) {
+                               $this->contentObjects[$name] = t3lib_div::makeInstance($fullyQualifiedClassName, $this);
+                       } else {
                                $this->contentObjects[$name] = NULL;
                        }
                }