From 3436317973ad1f703916a0a82ee16d5dd57efeb4 Mon Sep 17 00:00:00 2001
From: Alexander Schnitzler <git@alexanderschnitzler.de>
Date: Wed, 29 Nov 2017 11:08:35 +0100
Subject: [PATCH] [BUGFIX] Avoid reflection for public property injection

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>
---
 .../Classes/Object/Container/Container.php    | 10 ++++--
 .../Unit/Object/Container/ContainerTest.php   | 24 +++++++++++++
 .../ContainerPropertyInjectionTestClasses.php | 34 +++++++++++++++++++
 3 files changed, 65 insertions(+), 3 deletions(-)
 create mode 100644 typo3/sysext/extbase/Tests/Unit/Object/Container/Fixtures/ContainerPropertyInjectionTestClasses.php

diff --git a/typo3/sysext/extbase/Classes/Object/Container/Container.php b/typo3/sysext/extbase/Classes/Object/Container/Container.php
index 4d7682525385..24a86b2bae6f 100644
--- a/typo3/sysext/extbase/Classes/Object/Container/Container.php
+++ b/typo3/sysext/extbase/Classes/Object/Container/Container.php
@@ -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);
+            }
         }
     }
 
diff --git a/typo3/sysext/extbase/Tests/Unit/Object/Container/ContainerTest.php b/typo3/sysext/extbase/Tests/Unit/Object/Container/ContainerTest.php
index 91ef94bb8a03..735093f4841d 100644
--- a/typo3/sysext/extbase/Tests/Unit/Object/Container/ContainerTest.php
+++ b/typo3/sysext/extbase/Tests/Unit/Object/Container/ContainerTest.php
@@ -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
index 000000000000..f81af86fc2f1
--- /dev/null
+++ b/typo3/sysext/extbase/Tests/Unit/Object/Container/Fixtures/ContainerPropertyInjectionTestClasses.php
@@ -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;
+    }
+}
-- 
GitLab