[BUGFIX] Avoid reflection for public property injection 50/54850/5
authorAlexander Schnitzler <git@alexanderschnitzler.de>
Wed, 29 Nov 2017 10:08:35 +0000 (11:08 +0100)
committerSusanne Moog <susanne.moog@typo3.org>
Wed, 29 Nov 2017 19:12:40 +0000 (20:12 +0100)
The property injection in the ObjectContainer always
did reflect the object and made the property accessible,
even if the property was public and therefore accessible
by default.

With this patch, reflection is avoided for public
properties which increases the performance of public
property injection a lot.

Releases: master, 8.7
Resolves: #83155
Change-Id: I32f7c8e257f65da4a2fce1d7ee515d7954564387
Reviewed-on: https://review.typo3.org/54850
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Claus Due <claus@phpmind.net>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: Susanne Moog <susanne.moog@typo3.org>
Tested-by: Susanne Moog <susanne.moog@typo3.org>
typo3/sysext/extbase/Classes/Object/Container/Container.php
typo3/sysext/extbase/Tests/Unit/Object/Container/ContainerTest.php
typo3/sysext/extbase/Tests/Unit/Object/Container/Fixtures/ContainerPropertyInjectionTestClasses.php [new file with mode: 0644]

index 4d76825..24a86b2 100644 (file)
@@ -212,10 +212,14 @@ class Container implements \TYPO3\CMS\Core\SingletonInterface
             if ($classSchema->isSingleton() && !$instanceToInject instanceof \TYPO3\CMS\Core\SingletonInterface) {
                 $this->getLogger()->notice('The singleton "' . $classSchema->getClassName() . '" needs a prototype in "' . $injectPropertyName . '". This is often a bad code smell; often you rather want to inject a singleton.');
             }
-            $propertyReflection = new \ReflectionProperty($instance, $injectPropertyName);
 
-            $propertyReflection->setAccessible(true);
-            $propertyReflection->setValue($instance, $instanceToInject);
+            if ($classSchema->getProperty($injectPropertyName)['public']) {
+                $instance->{$injectPropertyName} = $instanceToInject;
+            } else {
+                $propertyReflection = new \ReflectionProperty($instance, $injectPropertyName);
+                $propertyReflection->setAccessible(true);
+                $propertyReflection->setValue($instance, $instanceToInject);
+            }
         }
     }
 
index 91ef94b..735093f 100644 (file)
@@ -15,9 +15,13 @@ namespace TYPO3\CMS\Extbase\Tests\Unit\Object\Container;
  */
 use Psr\Log\LoggerInterface;
 use TYPO3\CMS\Core\Log\Logger;
+use TYPO3\CMS\Extbase\Object\Container\Container;
 use TYPO3\CMS\Extbase\Object\Exception;
 use TYPO3\CMS\Extbase\Object\Exception\CannotBuildObjectException;
 use TYPO3\CMS\Extbase\Reflection\Exception\UnknownClassException;
+use TYPO3\CMS\Extbase\Tests\Unit\Object\Container\Fixtures\ArgumentTestClassForPublicPropertyInjection;
+use TYPO3\CMS\Extbase\Tests\Unit\Object\Container\Fixtures\ProtectedPropertyInjectClass;
+use TYPO3\CMS\Extbase\Tests\Unit\Object\Container\Fixtures\PublicPropertyInjectClass;
 
 /**
  * Test case
@@ -953,4 +957,24 @@ class ContainerTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
             $object->argumentTestClassTwo
         );
     }
+
+    /**
+     * @test
+     */
+    public function getInstanceInjectsPublicProperties()
+    {
+        $container = new Container();
+        $object = $container->getInstance(PublicPropertyInjectClass::class);
+        self::assertInstanceOf(ArgumentTestClassForPublicPropertyInjection::class, $object->foo);
+    }
+
+    /**
+     * @test
+     */
+    public function getInstanceInjectsProtectedProperties()
+    {
+        $container = new Container();
+        $object = $container->getInstance(ProtectedPropertyInjectClass::class);
+        self::assertInstanceOf(ArgumentTestClassForPublicPropertyInjection::class, $object->getFoo());
+    }
 }
diff --git a/typo3/sysext/extbase/Tests/Unit/Object/Container/Fixtures/ContainerPropertyInjectionTestClasses.php b/typo3/sysext/extbase/Tests/Unit/Object/Container/Fixtures/ContainerPropertyInjectionTestClasses.php
new file mode 100644 (file)
index 0000000..f81af86
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+declare(strict_types=1);
+
+namespace TYPO3\CMS\Extbase\Tests\Unit\Object\Container\Fixtures;
+
+use TYPO3\CMS\Extbase\Annotation\Inject;
+
+class PublicPropertyInjectClass
+{
+    /**
+     * @Inject
+     * @var \TYPO3\CMS\Extbase\Tests\Unit\Object\Container\Fixtures\ArgumentTestClassForPublicPropertyInjection
+     */
+    public $foo;
+}
+
+class ArgumentTestClassForPublicPropertyInjection
+{
+}
+
+class ProtectedPropertyInjectClass
+{
+
+    /**
+     * @Inject
+     * @var \TYPO3\CMS\Extbase\Tests\Unit\Object\Container\Fixtures\ArgumentTestClassForPublicPropertyInjection
+     */
+    protected $foo;
+
+    public function getFoo()
+    {
+        return $this->foo;
+    }
+}