From 5f11ab0c761d4a927ad86b27837696c5429a8b18 Mon Sep 17 00:00:00 2001 From: Christian Scheb Date: Tue, 20 Feb 2018 22:40:10 +0100 Subject: [PATCH 01/12] Add on-the-fly lazy loading --- composer.json | 6 +- .../injektor/DependencyInjectionContainer.php | 87 +++++++++++++++++-- .../DependencyInjectionContainerTest.php | 67 +++++++++++++- test/rg/injektor/test_classes.php | 43 +++++++++ 4 files changed, 193 insertions(+), 10 deletions(-) diff --git a/composer.json b/composer.json index d3e045b..f40a75d 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,11 @@ "psr/log": "~1.0.0" }, "require-dev": { - "phpunit/phpunit": "~7.0.0" + "phpunit/phpunit": "~7.0.0", + "ocramius/proxy-manager": "^2.1.0" + }, + "suggest": { + "ocramius/proxy-manager": "For lazy loading" }, "autoload": { "psr-0": { diff --git a/src/rg/injektor/DependencyInjectionContainer.php b/src/rg/injektor/DependencyInjectionContainer.php index beece13..bd4d0c4 100644 --- a/src/rg/injektor/DependencyInjectionContainer.php +++ b/src/rg/injektor/DependencyInjectionContainer.php @@ -10,6 +10,10 @@ namespace rg\injektor; use Doctrine\Common\Annotations\PhpParser; +use ProxyManager\Configuration as ProxyManagerConfiguration; +use ProxyManager\Factory\LazyLoadingValueHolderFactory; +use ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy; +use ProxyManager\Proxy\LazyLoadingInterface; use Psr\Log\LoggerInterface; use rg\injektor\annotations\Named; @@ -53,6 +57,16 @@ class DependencyInjectionContainer { */ private $logger; + /** + * @var bool + */ + private $supportsLazyLoading = false; + + /** + * @var LazyLoadingValueHolderFactory|null + */ + private $proxyFactory; + /** * used for injection loop detection * @@ -71,6 +85,7 @@ public function __construct(Configuration $config = null) { } $this->annotationReader = new SimpleAnnotationReader(); + $this->supportsLazyLoading = class_exists('ProxyManager\Configuration'); } /** @@ -197,11 +212,7 @@ public function getInstanceOfClass($fullClassName, array $constructorArguments = $instance = $classReflection->getMethod('getInstance')->invokeArgs(null, $constructorArguments); } else { $constructorArguments = $this->getConstructorArguments($classReflection, $classConfig, $constructorArguments); - if ($constructorArguments) { - $instance = $classReflection->newInstanceArgs($constructorArguments); - } else { - $instance = $classReflection->newInstanceArgs(array()); - } + $instance = $this->createNewInstance($classConfig, $classReflection, $constructorArguments); } $this->log('Created instance [' . spl_object_hash($instance) . '] of class [' . get_class($instance) . ']'); @@ -224,6 +235,26 @@ public function getInstanceOfClass($fullClassName, array $constructorArguments = return $instance; } + private function createNewInstance(array $classConfig, \ReflectionClass $classReflection, $constructorArguments) + { + $instanceConstructor = function () use ($classReflection, $constructorArguments) { + return $classReflection->newInstanceArgs($constructorArguments ? $constructorArguments : []); + }; + + if ($this->supportsLazyLoading && $this->isConfiguredAsLazy($classConfig, $classReflection)) { + return $this->getProxyFactory()->createProxy( + $classReflection->getName(), + function (&$wrappedObject, LazyLoadingInterface $proxy) use ($instanceConstructor) { + $proxy->setProxyInitializer(null); + $wrappedObject = $instanceConstructor(); + return true; + } + ); + } else { + return $instanceConstructor(); + } + } + /** * @param string $fullClassName * @param array $constructorArguments @@ -419,7 +450,22 @@ public function getClassReflection($fullClassName) { */ public function getProvidedConfiguredClass($classConfig, \ReflectionClass $classReflection, $name = null, $additionalArgumentsForProvider = array()) { if ($namedAnnotation = $this->getProviderClassName($classConfig, $classReflection, $name)) { - return $this->getRealClassInstanceFromProvider($namedAnnotation->getClassName(), $classReflection->name, array_merge($namedAnnotation->getParameters(), $additionalArgumentsForProvider)); + $instanceConstructor = function () use ($namedAnnotation, $classReflection, $additionalArgumentsForProvider) { + return $this->getRealClassInstanceFromProvider($namedAnnotation->getClassName(), $classReflection->name, array_merge($namedAnnotation->getParameters(), $additionalArgumentsForProvider)); + }; + + if ($this->supportsLazyLoading && $this->isConfiguredAsLazy($classConfig, $classReflection)) { + return $this->getProxyFactory()->createProxy( + $classReflection->name, + function (&$wrappedObject, LazyLoadingInterface $proxy) use ($instanceConstructor) { + $proxy->setProxyInitializer(null); + $wrappedObject = $instanceConstructor(); + return true; + } + ); + } else { + return $instanceConstructor(); + } } return null; @@ -599,6 +645,21 @@ public function isConfiguredAsService(array $classConfig, \ReflectionClass $clas return strpos($classComment, '@service') !== false; } + /** + * @param array $classConfig + * @param \ReflectionClass $classReflection + * @return bool + */ + public function isConfiguredAsLazy(array $classConfig, \ReflectionClass $classReflection) { + if (isset($classConfig['lazy'])) { + return (bool) $classConfig['lazy']; + } + + $classComment = $classReflection->getDocComment(); + + return strpos($classComment, '@lazy') !== false; + } + /** * @param object $object * @param string $methodName @@ -805,6 +866,20 @@ private function getImplementingClassBecauseOfName($argumentClass, $classConfig, return $classConfig['named'][$name]; } + /** + * @return LazyLoadingValueHolderFactory|null + */ + private function getProxyFactory() + { + if ($this->supportsLazyLoading && !$this->proxyFactory) { + $config = new ProxyManagerConfiguration(); + $config->setGeneratorStrategy(new EvaluatingGeneratorStrategy()); + $this->proxyFactory = new LazyLoadingValueHolderFactory($config); + } + + return $this->proxyFactory; + } + /** * @param $docComment * @return bool diff --git a/test/rg/injektor/DependencyInjectionContainerTest.php b/test/rg/injektor/DependencyInjectionContainerTest.php index 8700574..d1f4e10 100644 --- a/test/rg/injektor/DependencyInjectionContainerTest.php +++ b/test/rg/injektor/DependencyInjectionContainerTest.php @@ -202,9 +202,7 @@ public function testGetInstanceOfService() { public function testGetInstanceOfAnnotatedService() { $config = new Configuration(null, __DIR__ . '/_factories'); - $config->setClassConfig('rg\injektor\DICTestAnnotatedService', [ - 'service' => true - ]); + $config->setClassConfig('rg\injektor\DICTestAnnotatedService', []); $dic = $this->getContainer($config); $instance = $dic->getInstanceOfClass('rg\injektor\DICTestAnnotatedService', ['arg' => 123]); @@ -213,6 +211,69 @@ public function testGetInstanceOfAnnotatedService() { $this->assertSame($instance, $instanceTwo); } + public function testGetInstanceOfLazy() { + $config = new Configuration(null, __DIR__ . '/_factories'); + + $config->setClassConfig('rg\injektor\DICTestLazy', [ + 'lazy' => true + ]); + $dic = $this->getContainer($config); + $instance = $dic->getInstanceOfClass('rg\injektor\DICTestLazy', ['arg' => 123]); + + $this->assertInstanceOf('rg\injektor\DICTestLazy', $instance); + $this->assertInstanceOf('ProxyManager\Proxy\LazyLoadingInterface', $instance); + + $this->assertEquals('success', $instance->someMethod(), 'Must be able to call someMethod() on proxy object'); + } + + public function testGetInstanceOfAnnotatedLazy() { + $config = new Configuration(null, __DIR__ . '/_factories'); + + $config->setClassConfig('rg\injektor\DICTestAnnotatedLazy', []); + $dic = $this->getContainer($config); + $instance = $dic->getInstanceOfClass('rg\injektor\DICTestAnnotatedLazy', ['arg' => 123]); + + $this->assertInstanceOf('rg\injektor\DICTestAnnotatedLazy', $instance); + $this->assertInstanceOf('ProxyManager\Proxy\LazyLoadingInterface', $instance); + + $this->assertEquals('success', $instance->someMethod(), 'Must be able to call someMethod() on proxy object'); + } + + public function testGetInstanceOfLazyService() { + $config = new Configuration(null, __DIR__ . '/_factories'); + + $config->setClassConfig('rg\injektor\DICTestLazyService', [ + 'lazy' => true, + 'service' => true, + ]); + $dic = $this->getContainer($config); + $instance = $dic->getInstanceOfClass('rg\injektor\DICTestLazyService', ['arg' => 123]); + $instance2 = $dic->getInstanceOfClass('rg\injektor\DICTestLazyService', ['arg' => 123]); + + $this->assertSame($instance, $instance2); + + $this->assertInstanceOf('rg\injektor\DICTestLazyService', $instance); + $this->assertInstanceOf('ProxyManager\Proxy\LazyLoadingInterface', $instance); + + $this->assertEquals('success', $instance->someMethod(), 'Must be able to call someMethod() on proxy object'); + } + + public function testGetInstanceOfAnnotatedLazyService() { + $config = new Configuration(null, __DIR__ . '/_factories'); + + $config->setClassConfig('rg\injektor\DICTestAnnotatedLazyService', []); + $dic = $this->getContainer($config); + $instance = $dic->getInstanceOfClass('rg\injektor\DICTestAnnotatedLazyService', ['arg' => 123]); + $instance2 = $dic->getInstanceOfClass('rg\injektor\DICTestAnnotatedLazyService', ['arg' => 123]); + + $this->assertSame($instance, $instance2); + + $this->assertInstanceOf('rg\injektor\DICTestAnnotatedLazyService', $instance); + $this->assertInstanceOf('ProxyManager\Proxy\LazyLoadingInterface', $instance); + + $this->assertEquals('success', $instance->someMethod(), 'Must be able to call someMethod() on proxy object'); + } + public function testGetInstanceOfServiceWithDifferentArgumentsStillReturnSameInstance() { $config = new Configuration(null, __DIR__ . '/_factories'); diff --git a/test/rg/injektor/test_classes.php b/test/rg/injektor/test_classes.php index d0c2063..20e2fd0 100644 --- a/test/rg/injektor/test_classes.php +++ b/test/rg/injektor/test_classes.php @@ -441,6 +441,49 @@ public function __construct($arg) { } } + class DICTestLazy { + public function __construct($arg) { + + } + public function someMethod() { + return 'success'; + } + } + + /** + * @lazy + */ + class DICTestAnnotatedLazy { + public function __construct($arg) { + + } + public function someMethod() { + return 'success'; + } + } + + class DICTestLazyService { + public function __construct($arg) { + + } + public function someMethod() { + return 'success'; + } + } + + /** + * @lazy + * @service + */ + class DICTestAnnotatedLazyService { + public function __construct($arg) { + + } + public function someMethod() { + return 'success'; + } + } + class DICTestProvidedInterfaceImpl1 implements DICTestProvidedInterface { } From e4c91a5029e8ac770c81f97fdc44343ba770f593 Mon Sep 17 00:00:00 2001 From: Christian Scheb Date: Wed, 21 Feb 2018 00:15:43 +0100 Subject: [PATCH 02/12] Lazy loading generated factories --- .../injektor/DependencyInjectionContainer.php | 9 +- .../FactoryDependencyInjectionContainer.php | 2 +- ...actoryOnlyDependencyInjectionContainer.php | 1 + .../generators/CreateInstanceMethod.php | 20 ++++ src/rg/injektor/generators/FileGenerator.php | 109 +++++++++++------- .../injektor/generators/GetInstanceMethod.php | 20 ++++ src/rg/injektor/generators/InstanceMethod.php | 30 ----- 7 files changed, 116 insertions(+), 75 deletions(-) create mode 100644 src/rg/injektor/generators/CreateInstanceMethod.php create mode 100644 src/rg/injektor/generators/GetInstanceMethod.php delete mode 100644 src/rg/injektor/generators/InstanceMethod.php diff --git a/src/rg/injektor/DependencyInjectionContainer.php b/src/rg/injektor/DependencyInjectionContainer.php index bd4d0c4..e97a259 100644 --- a/src/rg/injektor/DependencyInjectionContainer.php +++ b/src/rg/injektor/DependencyInjectionContainer.php @@ -869,7 +869,7 @@ private function getImplementingClassBecauseOfName($argumentClass, $classConfig, /** * @return LazyLoadingValueHolderFactory|null */ - private function getProxyFactory() + protected function getProxyFactory() { if ($this->supportsLazyLoading && !$this->proxyFactory) { $config = new ProxyManagerConfiguration(); @@ -897,4 +897,11 @@ protected function log($string) { } } + /** + * @return bool + */ + public function supportsLazyLoading() + { + return $this->supportsLazyLoading; + } } diff --git a/src/rg/injektor/FactoryDependencyInjectionContainer.php b/src/rg/injektor/FactoryDependencyInjectionContainer.php index 78c4a3d..1f3698e 100755 --- a/src/rg/injektor/FactoryDependencyInjectionContainer.php +++ b/src/rg/injektor/FactoryDependencyInjectionContainer.php @@ -25,6 +25,7 @@ public function getInstanceOfClass($className, array $constructorArguments = arr $factoryClassName = $this->getFactoryClassName($className); if ($this->factoryClassExists($fullFactoryClassName, $factoryClassName)) { + $fullFactoryClassName::$proxyFactory = $this->getProxyFactory(); return $fullFactoryClassName::getInstance($constructorArguments); } @@ -114,5 +115,4 @@ protected function factoryClassExists($fullFactoryClassName, $factoryClassName) return false; } - } diff --git a/src/rg/injektor/FactoryOnlyDependencyInjectionContainer.php b/src/rg/injektor/FactoryOnlyDependencyInjectionContainer.php index b35bedc..07f908d 100644 --- a/src/rg/injektor/FactoryOnlyDependencyInjectionContainer.php +++ b/src/rg/injektor/FactoryOnlyDependencyInjectionContainer.php @@ -25,6 +25,7 @@ public function getInstanceOfClass($className, array $constructorArguments = arr $factoryClassName = $this->getFactoryClassName($className); if ($this->factoryClassExists($fullFactoryClassName, $factoryClassName)) { + $fullFactoryClassName::$proxyFactory = $this->getProxyFactory(); return $fullFactoryClassName::getInstance($constructorArguments); } diff --git a/src/rg/injektor/generators/CreateInstanceMethod.php b/src/rg/injektor/generators/CreateInstanceMethod.php new file mode 100644 index 0000000..ae370ff --- /dev/null +++ b/src/rg/injektor/generators/CreateInstanceMethod.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace rg\injektor\generators; + +class CreateInstanceMethod extends \Zend\Code\Generator\MethodGenerator { + + public function __construct() { + parent::__construct('createInstance', [], self::FLAG_PRIVATE | self::FLAG_STATIC); + + $parameter = new \Zend\Code\Generator\ParameterGenerator('parameters', 'array', array()); + $this->setParameter($parameter); + } +} diff --git a/src/rg/injektor/generators/FileGenerator.php b/src/rg/injektor/generators/FileGenerator.php index 42fd2c3..c6f7d89 100644 --- a/src/rg/injektor/generators/FileGenerator.php +++ b/src/rg/injektor/generators/FileGenerator.php @@ -99,7 +99,8 @@ public function getGeneratedFile() { $file = new Generator\FileGenerator(); $factoryClass = new \rg\injektor\generators\FactoryClass($factoryName); - $instanceMethod = new \rg\injektor\generators\InstanceMethod($this->factoryGenerator); + $createInstanceMethod = new \rg\injektor\generators\CreateInstanceMethod(); + $getInstanceMethod = new \rg\injektor\generators\GetInstanceMethod(); $arguments = array(); @@ -114,9 +115,48 @@ public function getGeneratedFile() { $isSingleton = $this->dic->isConfiguredAsSingleton($classConfig, $classReflection); $isService = $this->dic->isConfiguredAsService($classConfig, $classReflection); + $isLazy = $this->dic->supportsLazyLoading() && $this->dic->isConfiguredAsLazy($classConfig, $classReflection); - $body = '$i = 0;' . PHP_EOL; + $getInstanceBody = ''; + if ($isSingleton) { + $getInstanceBody .= '$singletonKey = serialize($parameters) . "#" . getmypid();' . PHP_EOL; + $getInstanceBody .= 'if (isset(self::$instance[$singletonKey])) {' . PHP_EOL; + $getInstanceBody .= ' return self::$instance[$singletonKey];' . PHP_EOL; + $getInstanceBody .= '}' . PHP_EOL . PHP_EOL; + } + + if ($isService) { + $getInstanceBody .= 'if (self::$instance) {' . PHP_EOL; + $getInstanceBody .= ' return self::$instance;' . PHP_EOL; + $getInstanceBody .= '}' . PHP_EOL . PHP_EOL; + } + + if ($isLazy) { + $getInstanceBody .= '$instance = self::$proxyFactory->createProxy(' . PHP_EOL; + $getInstanceBody .= ' \'' . $classReflection->getName() . '\',' . PHP_EOL; + $getInstanceBody .= ' function (&$wrappedObject, $proxy) use ($parameters) {' . PHP_EOL; + $getInstanceBody .= ' $proxy->setProxyInitializer(null);' . PHP_EOL; + $getInstanceBody .= ' $wrappedObject = ' . $factoryName . '::createInstance($parameters);' . PHP_EOL; + $getInstanceBody .= ' return true;' . PHP_EOL; + $getInstanceBody .= ' }' . PHP_EOL; + $getInstanceBody .= ');' . PHP_EOL; + } else { + $getInstanceBody .= '$instance = self::createInstance($parameters);' . PHP_EOL; + } + + if ($isSingleton) { + $getInstanceBody .= 'self::$instance[$singletonKey] = $instance;' . PHP_EOL; + } + if ($isService) { + $getInstanceBody .= 'self::$instance = $instance;' . PHP_EOL; + } + + $getInstanceBody .= 'return $instance;' . PHP_EOL; + $getInstanceMethod->setBody($getInstanceBody); + $factoryClass->addMethodFromGenerator($getInstanceMethod); + + $createInstanceBody = '$i = 0;' . PHP_EOL; if ($isSingleton || $isService) { $defaultValue = new Generator\PropertyValueGenerator(array(), Generator\ValueGenerator::TYPE_ARRAY, Generator\ValueGenerator::OUTPUT_SINGLE_LINE); $property = new Generator\PropertyGenerator('instance', $defaultValue, Generator\PropertyGenerator::FLAG_PRIVATE); @@ -124,24 +164,15 @@ public function getGeneratedFile() { $factoryClass->addPropertyFromGenerator($property); } - if ($isSingleton) { - $body .= '$singletonKey = serialize($parameters) . "#" . getmypid();' . PHP_EOL; - $body .= 'if (isset(self::$instance[$singletonKey])) {' . PHP_EOL; - $body .= ' return self::$instance[$singletonKey];' . PHP_EOL; - $body .= '}' . PHP_EOL . PHP_EOL; - } - - if ($isService) { - $body .= 'if (self::$instance) {' . PHP_EOL; - $body .= ' return self::$instance;' . PHP_EOL; - $body .= '}' . PHP_EOL . PHP_EOL; - } + $property = new Generator\PropertyGenerator('proxyFactory', null, Generator\PropertyGenerator::FLAG_PUBLIC); + $property->setStatic(true); + $factoryClass->addPropertyFromGenerator($property); $providerClassName = $this->dic->getProviderClassName($classConfig, new \ReflectionClass($this->fullClassName), null); if ($providerClassName && $providerClassName->getClassName()) { $argumentFactory = $this->dic->getFullFactoryClassName($providerClassName->getClassName()); $this->factoryGenerator->processFileForClass($providerClassName->getClassName()); - $body .= '$instance = \\' . $argumentFactory . '::getInstance(array())->get();' . PHP_EOL; + $createInstanceBody .= '$instance = \\' . $argumentFactory . '::getInstance(array())->get();' . PHP_EOL; $this->usedFactories[] = $argumentFactory; } else { // constructor method arguments @@ -156,7 +187,7 @@ public function getGeneratedFile() { } - $body .= 'if (!$parameters) {' . PHP_EOL; + $createInstanceBody .= 'if (!$parameters) {' . PHP_EOL; foreach ($arguments as $argument) { /** @var \ReflectionParameter $argument */ @@ -176,14 +207,14 @@ public function getGeneratedFile() { if ($injectionParameter->getFactoryName()) { $this->usedFactories[] = $injectionParameter->getFactoryName(); } - $body .= ' ' . $injectionParameter->getProcessingBody(); + $createInstanceBody .= ' ' . $injectionParameter->getProcessingBody(); } catch (\Exception $e) { - $body .= ' ' . $injectionParameter->getDefaultProcessingBody(); + $createInstanceBody .= ' ' . $injectionParameter->getDefaultProcessingBody(); } } - $body .= '}' . PHP_EOL; - $body .= 'else if (array_key_exists(0, $parameters)) {' . PHP_EOL; + $createInstanceBody .= '}' . PHP_EOL; + $createInstanceBody .= 'else if (array_key_exists(0, $parameters)) {' . PHP_EOL; foreach ($arguments as $argument) { /** @var \ReflectionParameter $argument */ @@ -203,14 +234,14 @@ public function getGeneratedFile() { if ($injectionParameter->getFactoryName()) { $this->usedFactories[] = $injectionParameter->getFactoryName(); } - $body .= ' ' . $injectionParameter->getProcessingBody(); + $createInstanceBody .= ' ' . $injectionParameter->getProcessingBody(); } catch (\Exception $e) { - $body .= ' ' . $injectionParameter->getDefaultProcessingBody(); + $createInstanceBody .= ' ' . $injectionParameter->getDefaultProcessingBody(); } } - $body .= '}' . PHP_EOL; - $body .= 'else {' . PHP_EOL; + $createInstanceBody .= '}' . PHP_EOL; + $createInstanceBody .= 'else {' . PHP_EOL; foreach ($arguments as $argument) { /** @var \ReflectionParameter $argument */ @@ -230,13 +261,13 @@ public function getGeneratedFile() { if ($injectionParameter->getFactoryName()) { $this->usedFactories[] = $injectionParameter->getFactoryName(); } - $body .= ' ' . $injectionParameter->getProcessingBody(); + $createInstanceBody .= ' ' . $injectionParameter->getProcessingBody(); } catch (\Exception $e) { - $body .= ' ' . $injectionParameter->getDefaultProcessingBody(); + $createInstanceBody .= ' ' . $injectionParameter->getDefaultProcessingBody(); } } - $body .= '}' . PHP_EOL; + $createInstanceBody .= '}' . PHP_EOL; } // Property injection @@ -246,36 +277,28 @@ public function getGeneratedFile() { $proxyName = $this->dic->getProxyClassName($this->fullClassName); if ($this->dic->isSingleton($classReflection)) { $file->setClass($this->createProxyClass($proxyName)); - $body .= PHP_EOL . '$instance = ' . $proxyName . '::getInstance(' . implode(', ', $this->constructorArgumentStringParts) . ');' . PHP_EOL; + $createInstanceBody .= PHP_EOL . '$instance = ' . $proxyName . '::getInstance(' . implode(', ', $this->constructorArgumentStringParts) . ');' . PHP_EOL; } else { $file->setClass($this->createProxyClass($proxyName)); - $body .= PHP_EOL . '$instance = new ' . $proxyName . '(' . implode(', ', $this->constructorArgumentStringParts) . ');' . PHP_EOL; + $createInstanceBody .= PHP_EOL . '$instance = new ' . $proxyName . '(' . implode(', ', $this->constructorArgumentStringParts) . ');' . PHP_EOL; } } else { if ($this->dic->isSingleton($classReflection)) { - $body .= PHP_EOL . '$instance = \\' . $this->fullClassName . '::getInstance(' . implode(', ', $this->constructorArgumentStringParts) . ');' . PHP_EOL; + $createInstanceBody .= PHP_EOL . '$instance = \\' . $this->fullClassName . '::getInstance(' . implode(', ', $this->constructorArgumentStringParts) . ');' . PHP_EOL; } else { - $body .= PHP_EOL . '$instance = new \\' . $this->fullClassName . '(' . implode(', ', $this->constructorArgumentStringParts) . ');' . PHP_EOL; + $createInstanceBody .= PHP_EOL . '$instance = new \\' . $this->fullClassName . '(' . implode(', ', $this->constructorArgumentStringParts) . ');' . PHP_EOL; } } } - if ($isSingleton) { - $body .= 'self::$instance[$singletonKey] = $instance;' . PHP_EOL; - } - if ($isService) { - $body .= 'self::$instance = $instance;' . PHP_EOL; - } - foreach ($this->injectableArguments as $injectableArgument) { - $body .= '$instance->propertyInjection' . $injectableArgument->getName() . '();' . PHP_EOL; + $createInstanceBody .= '$instance->propertyInjection' . $injectableArgument->getName() . '();' . PHP_EOL; } - $body .= 'return $instance;' . PHP_EOL; + $createInstanceBody .= 'return $instance;' . PHP_EOL; - $instanceMethod->setBody($body); - $instanceMethod->setStatic(true); - $factoryClass->addMethodFromGenerator($instanceMethod); + $createInstanceMethod->setBody($createInstanceBody); + $factoryClass->addMethodFromGenerator($createInstanceMethod); // Add Factory Method $methods = $classReflection->getMethods(); diff --git a/src/rg/injektor/generators/GetInstanceMethod.php b/src/rg/injektor/generators/GetInstanceMethod.php new file mode 100644 index 0000000..c1bdbcd --- /dev/null +++ b/src/rg/injektor/generators/GetInstanceMethod.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace rg\injektor\generators; + +class GetInstanceMethod extends \Zend\Code\Generator\MethodGenerator { + + public function __construct() { + parent::__construct('getInstance', [], self::FLAG_PUBLIC | self::FLAG_STATIC); + + $parameter = new \Zend\Code\Generator\ParameterGenerator('parameters', 'array', array()); + $this->setParameter($parameter); + } +} diff --git a/src/rg/injektor/generators/InstanceMethod.php b/src/rg/injektor/generators/InstanceMethod.php deleted file mode 100644 index 9571fc0..0000000 --- a/src/rg/injektor/generators/InstanceMethod.php +++ /dev/null @@ -1,30 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace rg\injektor\generators; - -class InstanceMethod extends \Zend\Code\Generator\MethodGenerator { - - /** - * @var \rg\injektor\generators\FactoryGenerator - */ - private $factoryGenerator; - - /** - * @param \rg\injektor\generators\FactoryGenerator $factoryGenerator - */ - public function __construct(FactoryGenerator $factoryGenerator) { - parent::__construct('getInstance'); - - $this->factoryGenerator = $factoryGenerator; - - $parameter = new \Zend\Code\Generator\ParameterGenerator('parameters', 'array', array()); - $this->setParameter($parameter); - } -} \ No newline at end of file From 90d7a10c07ee0af4a01e34bbfbe66b4d9b7920a2 Mon Sep 17 00:00:00 2001 From: Christian Scheb Date: Wed, 21 Feb 2018 10:07:49 +0100 Subject: [PATCH 03/12] Add .idea folder to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 8c59329..d3a03a7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.idea /build/ /vendor/ /composer.phar From 9806d174c9726211156225276fd12c486db63268 Mon Sep 17 00:00:00 2001 From: Christian Scheb Date: Wed, 21 Feb 2018 10:43:38 +0100 Subject: [PATCH 04/12] Update FactoryGeneratorTest --- .../generators/FactoryGeneratorTest.php | 55 ++++++++++++++++--- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/test/rg/injektor/generators/FactoryGeneratorTest.php b/test/rg/injektor/generators/FactoryGeneratorTest.php index b4f5f5b..0636f80 100644 --- a/test/rg/injektor/generators/FactoryGeneratorTest.php +++ b/test/rg/injektor/generators/FactoryGeneratorTest.php @@ -31,7 +31,7 @@ public function testGenerateFactory($file, $content) { 'singleton' => true )); $config->setClassConfig('rg\injektor\generators\FGTestClassFour', array( - 'singleton' => true + 'service' => true )); $config->setClassConfig('rg\injektor\generators\FGTestClassThree', array( 'params' => array( @@ -59,7 +59,15 @@ public function provider() { class rg_injektor_generators_FGTestClassSimpleFactory { + public static \$proxyFactory = null; + public static function getInstance(array \$parameters = []) + { + \$instance = self::createInstance(\$parameters); + return \$instance; + } + + private static function createInstance(array \$parameters = []) { \$i = 0; @@ -97,14 +105,22 @@ class rg_injektor_generators_FGTestClassFourFactory private static \$instance = []; + public static \$proxyFactory = null; + public static function getInstance(array \$parameters = []) { - \$i = 0; - \$singletonKey = serialize(\$parameters) . "#" . getmypid(); - if (isset(self::\$instance[\$singletonKey])) { - return self::\$instance[\$singletonKey]; + if (self::\$instance) { + return self::\$instance; } + \$instance = self::createInstance(\$parameters); + self::\$instance = \$instance; + return \$instance; + } + + private static function createInstance(array \$parameters = []) + { + \$i = 0; if (!\$parameters) { \$simple = \\rg\injektor\generated\\rg_injektor_generators_FGTestClassSimpleFactory::getInstance(array ( )); @@ -119,7 +135,6 @@ public static function getInstance(array \$parameters = []) } \$instance = rg_injektor_generators_FGTestClassFourProxy::getInstance(\$simple); - self::\$instance[\$singletonKey] = \$instance; \$instance->propertyInjectioninjectedProperty(); return \$instance; } @@ -161,7 +176,15 @@ public static function callGetInstance(\$object, array \$parameters = []) class rg_injektor_generators_FGTestClassThreeFactory { + public static \$proxyFactory = null; + public static function getInstance(array \$parameters = []) + { + \$instance = self::createInstance(\$parameters); + return \$instance; + } + + private static function createInstance(array \$parameters = []) { \$i = 0; if (!\$parameters) { @@ -210,7 +233,15 @@ public static function callGetSomething(\$object) class rg_injektor_generators_FGTestClassTwoFactory { + public static \$proxyFactory = null; + public static function getInstance(array \$parameters = []) + { + \$instance = self::createInstance(\$parameters); + return \$instance; + } + + private static function createInstance(array \$parameters = []) { \$i = 0; if (!\$parameters) { @@ -270,14 +301,23 @@ class rg_injektor_generators_FGTestClassOneFactory private static \$instance = []; + public static \$proxyFactory = null; + public static function getInstance(array \$parameters = []) { - \$i = 0; \$singletonKey = serialize(\$parameters) . "#" . getmypid(); if (isset(self::\$instance[\$singletonKey])) { return self::\$instance[\$singletonKey]; } + \$instance = self::createInstance(\$parameters); + self::\$instance[\$singletonKey] = \$instance; + return \$instance; + } + + private static function createInstance(array \$parameters = []) + { + \$i = 0; if (!\$parameters) { \$two = \\rg\injektor\generated\\rg_injektor_generators_FGTestClassTwoFactory::getInstance(array ( )); @@ -298,7 +338,6 @@ public static function getInstance(array \$parameters = []) } \$instance = new rg_injektor_generators_FGTestClassOneProxy(\$two, \$three); - self::\$instance[\$singletonKey] = \$instance; \$instance->propertyInjectionfour(); return \$instance; } From 17312de97778a5b8d9787d854962a2b2f055ebd7 Mon Sep 17 00:00:00 2001 From: Christian Scheb Date: Thu, 22 Feb 2018 13:54:00 +0100 Subject: [PATCH 05/12] Generate lazy proxy together with the factory into the same file --- .../injektor/DependencyInjectionContainer.php | 69 ++++++---- .../FactoryDependencyInjectionContainer.php | 9 +- ...actoryOnlyDependencyInjectionContainer.php | 1 - src/rg/injektor/generators/FileGenerator.php | 118 ++++++++++-------- .../generators/FactoryGeneratorTest.php | 53 ++------ 5 files changed, 130 insertions(+), 120 deletions(-) diff --git a/src/rg/injektor/DependencyInjectionContainer.php b/src/rg/injektor/DependencyInjectionContainer.php index e97a259..34d27d0 100644 --- a/src/rg/injektor/DependencyInjectionContainer.php +++ b/src/rg/injektor/DependencyInjectionContainer.php @@ -65,7 +65,7 @@ class DependencyInjectionContainer { /** * @var LazyLoadingValueHolderFactory|null */ - private $proxyFactory; + private $lazyProxyFactory; /** * used for injection loop detection @@ -235,6 +235,13 @@ public function getInstanceOfClass($fullClassName, array $constructorArguments = return $instance; } + /** + * @param array $classConfig + * @param \ReflectionClass $classReflection + * @param array $constructorArguments + * + * @return object + */ private function createNewInstance(array $classConfig, \ReflectionClass $classReflection, $constructorArguments) { $instanceConstructor = function () use ($classReflection, $constructorArguments) { @@ -242,19 +249,33 @@ private function createNewInstance(array $classConfig, \ReflectionClass $classRe }; if ($this->supportsLazyLoading && $this->isConfiguredAsLazy($classConfig, $classReflection)) { - return $this->getProxyFactory()->createProxy( - $classReflection->getName(), - function (&$wrappedObject, LazyLoadingInterface $proxy) use ($instanceConstructor) { - $proxy->setProxyInitializer(null); - $wrappedObject = $instanceConstructor(); - return true; - } - ); + return $this->wrapInstanceWithLazyProxy($classReflection->getName(), $instanceConstructor); } else { return $instanceConstructor(); } } + /** + * @param string $className + * @param callable $instanceConstructor + * + * @return \ProxyManager\Proxy\VirtualProxyInterface + */ + private function wrapInstanceWithLazyProxy($className, $instanceConstructor) { + $proxyParameters = [ + + ]; + return $this->getLazyProxyFactory()->createProxy( + $className, + function (&$wrappedObject, LazyLoadingInterface $proxy) use ($instanceConstructor) { + $proxy->setProxyInitializer(null); + $wrappedObject = $instanceConstructor(); + return true; + }, + $proxyParameters + ); + } + /** * @param string $fullClassName * @param array $constructorArguments @@ -455,14 +476,7 @@ public function getProvidedConfiguredClass($classConfig, \ReflectionClass $class }; if ($this->supportsLazyLoading && $this->isConfiguredAsLazy($classConfig, $classReflection)) { - return $this->getProxyFactory()->createProxy( - $classReflection->name, - function (&$wrappedObject, LazyLoadingInterface $proxy) use ($instanceConstructor) { - $proxy->setProxyInitializer(null); - $wrappedObject = $instanceConstructor(); - return true; - } - ); + return $this->wrapInstanceWithLazyProxy($classReflection->name, $instanceConstructor); } else { return $instanceConstructor(); } @@ -866,18 +880,25 @@ private function getImplementingClassBecauseOfName($argumentClass, $classConfig, return $classConfig['named'][$name]; } + /** + * @return \ProxyManager\Configuration + */ + private function getLazyProxyFactoryConfiguration() { + $config = new ProxyManagerConfiguration(); + $config->setGeneratorStrategy(new EvaluatingGeneratorStrategy()); + return $config; + } + /** * @return LazyLoadingValueHolderFactory|null */ - protected function getProxyFactory() - { - if ($this->supportsLazyLoading && !$this->proxyFactory) { - $config = new ProxyManagerConfiguration(); - $config->setGeneratorStrategy(new EvaluatingGeneratorStrategy()); - $this->proxyFactory = new LazyLoadingValueHolderFactory($config); + private function getLazyProxyFactory() { + if ($this->supportsLazyLoading && !$this->lazyProxyFactory) { + $config = $this->getLazyProxyFactoryConfiguration(); + $this->lazyProxyFactory = new LazyLoadingValueHolderFactory($config); } - return $this->proxyFactory; + return $this->lazyProxyFactory; } /** diff --git a/src/rg/injektor/FactoryDependencyInjectionContainer.php b/src/rg/injektor/FactoryDependencyInjectionContainer.php index 1f3698e..d50fb75 100755 --- a/src/rg/injektor/FactoryDependencyInjectionContainer.php +++ b/src/rg/injektor/FactoryDependencyInjectionContainer.php @@ -25,7 +25,6 @@ public function getInstanceOfClass($className, array $constructorArguments = arr $factoryClassName = $this->getFactoryClassName($className); if ($this->factoryClassExists($fullFactoryClassName, $factoryClassName)) { - $fullFactoryClassName::$proxyFactory = $this->getProxyFactory(); return $fullFactoryClassName::getInstance($constructorArguments); } @@ -80,6 +79,14 @@ public function getProxyClassName($fullClassName) { return self::$prefix . $this->getStrippedClassName($fullClassName) . 'Proxy'; } + /** + * @param $fullClassName + * @return string + */ + public function getLazyProxyClassName($fullClassName) { + return self::$prefix . $this->getStrippedClassName($fullClassName) . 'Lazy'; + } + /** * @param string $fullClassName * @return string diff --git a/src/rg/injektor/FactoryOnlyDependencyInjectionContainer.php b/src/rg/injektor/FactoryOnlyDependencyInjectionContainer.php index 07f908d..b35bedc 100644 --- a/src/rg/injektor/FactoryOnlyDependencyInjectionContainer.php +++ b/src/rg/injektor/FactoryOnlyDependencyInjectionContainer.php @@ -25,7 +25,6 @@ public function getInstanceOfClass($className, array $constructorArguments = arr $factoryClassName = $this->getFactoryClassName($className); if ($this->factoryClassExists($fullFactoryClassName, $factoryClassName)) { - $fullFactoryClassName::$proxyFactory = $this->getProxyFactory(); return $fullFactoryClassName::getInstance($constructorArguments); } diff --git a/src/rg/injektor/generators/FileGenerator.php b/src/rg/injektor/generators/FileGenerator.php index c6f7d89..d04922e 100644 --- a/src/rg/injektor/generators/FileGenerator.php +++ b/src/rg/injektor/generators/FileGenerator.php @@ -8,6 +8,8 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ +use ProxyManager\Generator\ClassGenerator; +use ProxyManager\ProxyGenerator\LazyLoadingValueHolderGenerator; use Zend\Code\Generator; use rg\injektor\Configuration; use rg\injektor\FactoryDependencyInjectionContainer; @@ -89,6 +91,7 @@ public function __construct(FactoryGenerator $factoryGenerator, Configuration $c public function getGeneratedFile() { $classConfig = $this->config->getClassConfig($this->fullClassName); $factoryName = $this->dic->getFactoryClassName($this->fullClassName); + $lazyProxyClassName = null; $classReflection = $this->dic->getClassReflection($this->fullClassName); @@ -99,8 +102,8 @@ public function getGeneratedFile() { $file = new Generator\FileGenerator(); $factoryClass = new \rg\injektor\generators\FactoryClass($factoryName); - $createInstanceMethod = new \rg\injektor\generators\CreateInstanceMethod(); $getInstanceMethod = new \rg\injektor\generators\GetInstanceMethod(); + $createInstanceMethod = new \rg\injektor\generators\CreateInstanceMethod(); $arguments = array(); @@ -117,45 +120,6 @@ public function getGeneratedFile() { $isService = $this->dic->isConfiguredAsService($classConfig, $classReflection); $isLazy = $this->dic->supportsLazyLoading() && $this->dic->isConfiguredAsLazy($classConfig, $classReflection); - $getInstanceBody = ''; - if ($isSingleton) { - $getInstanceBody .= '$singletonKey = serialize($parameters) . "#" . getmypid();' . PHP_EOL; - $getInstanceBody .= 'if (isset(self::$instance[$singletonKey])) {' . PHP_EOL; - $getInstanceBody .= ' return self::$instance[$singletonKey];' . PHP_EOL; - $getInstanceBody .= '}' . PHP_EOL . PHP_EOL; - } - - if ($isService) { - $getInstanceBody .= 'if (self::$instance) {' . PHP_EOL; - $getInstanceBody .= ' return self::$instance;' . PHP_EOL; - $getInstanceBody .= '}' . PHP_EOL . PHP_EOL; - } - - if ($isLazy) { - $getInstanceBody .= '$instance = self::$proxyFactory->createProxy(' . PHP_EOL; - $getInstanceBody .= ' \'' . $classReflection->getName() . '\',' . PHP_EOL; - $getInstanceBody .= ' function (&$wrappedObject, $proxy) use ($parameters) {' . PHP_EOL; - $getInstanceBody .= ' $proxy->setProxyInitializer(null);' . PHP_EOL; - $getInstanceBody .= ' $wrappedObject = ' . $factoryName . '::createInstance($parameters);' . PHP_EOL; - $getInstanceBody .= ' return true;' . PHP_EOL; - $getInstanceBody .= ' }' . PHP_EOL; - $getInstanceBody .= ');' . PHP_EOL; - } else { - $getInstanceBody .= '$instance = self::createInstance($parameters);' . PHP_EOL; - } - - if ($isSingleton) { - $getInstanceBody .= 'self::$instance[$singletonKey] = $instance;' . PHP_EOL; - } - if ($isService) { - $getInstanceBody .= 'self::$instance = $instance;' . PHP_EOL; - } - - $getInstanceBody .= 'return $instance;' . PHP_EOL; - - $getInstanceMethod->setBody($getInstanceBody); - $factoryClass->addMethodFromGenerator($getInstanceMethod); - $createInstanceBody = '$i = 0;' . PHP_EOL; if ($isSingleton || $isService) { $defaultValue = new Generator\PropertyValueGenerator(array(), Generator\ValueGenerator::TYPE_ARRAY, Generator\ValueGenerator::OUTPUT_SINGLE_LINE); @@ -164,11 +128,8 @@ public function getGeneratedFile() { $factoryClass->addPropertyFromGenerator($property); } - $property = new Generator\PropertyGenerator('proxyFactory', null, Generator\PropertyGenerator::FLAG_PUBLIC); - $property->setStatic(true); - $factoryClass->addPropertyFromGenerator($property); - - $providerClassName = $this->dic->getProviderClassName($classConfig, new \ReflectionClass($this->fullClassName), null); + $fullClassNameRefection = new \ReflectionClass($this->fullClassName); + $providerClassName = $this->dic->getProviderClassName($classConfig, $fullClassNameRefection, null); if ($providerClassName && $providerClassName->getClassName()) { $argumentFactory = $this->dic->getFullFactoryClassName($providerClassName->getClassName()); $this->factoryGenerator->processFileForClass($providerClassName->getClassName()); @@ -291,14 +252,66 @@ public function getGeneratedFile() { } } + // Make the newly created instance immediately available for property injection + if ($isSingleton) { + $createInstanceBody .= '$singletonKey = serialize($parameters) . "#" . getmypid();' . PHP_EOL; + $createInstanceBody .= 'self::$instance[$singletonKey] = $instance;' . PHP_EOL; + } + if ($isService) { + $createInstanceBody .= 'self::$instance = $instance;' . PHP_EOL; + } + foreach ($this->injectableArguments as $injectableArgument) { $createInstanceBody .= '$instance->propertyInjection' . $injectableArgument->getName() . '();' . PHP_EOL; } - $createInstanceBody .= 'return $instance;' . PHP_EOL; + $getInstanceBody = ''; + if ($isSingleton) { + $getInstanceBody .= '$singletonKey = serialize($parameters) . "#" . getmypid();' . PHP_EOL; + $getInstanceBody .= 'if (isset(self::$instance[$singletonKey])) {' . PHP_EOL; + $getInstanceBody .= ' return self::$instance[$singletonKey];' . PHP_EOL; + $getInstanceBody .= '}' . PHP_EOL . PHP_EOL; + } + + if ($isService) { + $getInstanceBody .= 'if (self::$instance) {' . PHP_EOL; + $getInstanceBody .= ' return self::$instance;' . PHP_EOL; + $getInstanceBody .= '}' . PHP_EOL . PHP_EOL; + } + + if ($isLazy) { + // Create + $lazyProxyClassName = $this->dic->getLazyProxyClassName($this->fullClassName); + $getInstanceBody .= '$instance = ' . $lazyProxyClassName . '::staticProxyConstructor(' . PHP_EOL; + $getInstanceBody .= ' function (&$wrappedObject, $proxy) use ($parameters) {' . PHP_EOL; + $getInstanceBody .= ' $proxy->setProxyInitializer(null);' . PHP_EOL; + $getInstanceBody .= ' $wrappedObject = ' . $factoryName . '::createInstance($parameters);' . PHP_EOL; + $getInstanceBody .= ' return true;' . PHP_EOL; + $getInstanceBody .= ' }' . PHP_EOL; + $getInstanceBody .= ');' . PHP_EOL; + $getInstanceBody .= ''; + + // Store the service/singleton instance + if ($isSingleton) { + $getInstanceBody .= '$singletonKey = serialize($parameters) . "#" . getmypid();' . PHP_EOL; + $getInstanceBody .= 'self::$instance[$singletonKey] = $instance;' . PHP_EOL; + } + if ($isService) { + $getInstanceBody .= 'self::$instance = $instance;' . PHP_EOL; + } + + // Create instance method + $createInstanceBody .= 'return $instance;' . PHP_EOL; + $createInstanceMethod->setBody($createInstanceBody); + $factoryClass->addMethodFromGenerator($createInstanceMethod); + } else { + $getInstanceBody .= $createInstanceBody; + } + + $getInstanceBody .= 'return $instance;' . PHP_EOL; - $createInstanceMethod->setBody($createInstanceBody); - $factoryClass->addMethodFromGenerator($createInstanceMethod); + $getInstanceMethod->setBody($getInstanceBody); + $factoryClass->addMethodFromGenerator($getInstanceMethod); // Add Factory Method $methods = $classReflection->getMethods(); @@ -313,7 +326,6 @@ public function getGeneratedFile() { } // Generate File - $file->setNamespace('rg\injektor\generated'); $this->usedFactories = array_unique($this->usedFactories); foreach ($this->usedFactories as &$usedFactory) { @@ -324,6 +336,14 @@ public function getGeneratedFile() { $file->setClass($factoryClass); $file->setFilename($this->factoryPath . DIRECTORY_SEPARATOR . $factoryName . '.php'); + // Add lazy proxy class + if ($isLazy) { + $proxyGenerator = new LazyLoadingValueHolderGenerator(); + $generatedClass = new ClassGenerator($lazyProxyClassName); + $proxyGenerator->generate($fullClassNameRefection, $generatedClass); + $file->setClass($generatedClass); + } + return $file; } diff --git a/test/rg/injektor/generators/FactoryGeneratorTest.php b/test/rg/injektor/generators/FactoryGeneratorTest.php index 0636f80..dc1467f 100644 --- a/test/rg/injektor/generators/FactoryGeneratorTest.php +++ b/test/rg/injektor/generators/FactoryGeneratorTest.php @@ -31,7 +31,7 @@ public function testGenerateFactory($file, $content) { 'singleton' => true )); $config->setClassConfig('rg\injektor\generators\FGTestClassFour', array( - 'service' => true + 'singleton' => true )); $config->setClassConfig('rg\injektor\generators\FGTestClassThree', array( 'params' => array( @@ -59,15 +59,7 @@ public function provider() { class rg_injektor_generators_FGTestClassSimpleFactory { - public static \$proxyFactory = null; - public static function getInstance(array \$parameters = []) - { - \$instance = self::createInstance(\$parameters); - return \$instance; - } - - private static function createInstance(array \$parameters = []) { \$i = 0; @@ -105,21 +97,13 @@ class rg_injektor_generators_FGTestClassFourFactory private static \$instance = []; - public static \$proxyFactory = null; - public static function getInstance(array \$parameters = []) { - if (self::\$instance) { - return self::\$instance; + \$singletonKey = serialize(\$parameters) . "#" . getmypid(); + if (isset(self::\$instance[\$singletonKey])) { + return self::\$instance[\$singletonKey]; } - \$instance = self::createInstance(\$parameters); - self::\$instance = \$instance; - return \$instance; - } - - private static function createInstance(array \$parameters = []) - { \$i = 0; if (!\$parameters) { \$simple = \\rg\injektor\generated\\rg_injektor_generators_FGTestClassSimpleFactory::getInstance(array ( @@ -135,6 +119,8 @@ private static function createInstance(array \$parameters = []) } \$instance = rg_injektor_generators_FGTestClassFourProxy::getInstance(\$simple); + \$singletonKey = serialize(\$parameters) . "#" . getmypid(); + self::\$instance[\$singletonKey] = \$instance; \$instance->propertyInjectioninjectedProperty(); return \$instance; } @@ -176,15 +162,7 @@ public static function callGetInstance(\$object, array \$parameters = []) class rg_injektor_generators_FGTestClassThreeFactory { - public static \$proxyFactory = null; - public static function getInstance(array \$parameters = []) - { - \$instance = self::createInstance(\$parameters); - return \$instance; - } - - private static function createInstance(array \$parameters = []) { \$i = 0; if (!\$parameters) { @@ -233,15 +211,7 @@ public static function callGetSomething(\$object) class rg_injektor_generators_FGTestClassTwoFactory { - public static \$proxyFactory = null; - public static function getInstance(array \$parameters = []) - { - \$instance = self::createInstance(\$parameters); - return \$instance; - } - - private static function createInstance(array \$parameters = []) { \$i = 0; if (!\$parameters) { @@ -301,8 +271,6 @@ class rg_injektor_generators_FGTestClassOneFactory private static \$instance = []; - public static \$proxyFactory = null; - public static function getInstance(array \$parameters = []) { \$singletonKey = serialize(\$parameters) . "#" . getmypid(); @@ -310,13 +278,6 @@ public static function getInstance(array \$parameters = []) return self::\$instance[\$singletonKey]; } - \$instance = self::createInstance(\$parameters); - self::\$instance[\$singletonKey] = \$instance; - return \$instance; - } - - private static function createInstance(array \$parameters = []) - { \$i = 0; if (!\$parameters) { \$two = \\rg\injektor\generated\\rg_injektor_generators_FGTestClassTwoFactory::getInstance(array ( @@ -338,6 +299,8 @@ private static function createInstance(array \$parameters = []) } \$instance = new rg_injektor_generators_FGTestClassOneProxy(\$two, \$three); + \$singletonKey = serialize(\$parameters) . "#" . getmypid(); + self::\$instance[\$singletonKey] = \$instance; \$instance->propertyInjectionfour(); return \$instance; } From 9b9eead0bd5b983873449d5df0970fd919cd18ba Mon Sep 17 00:00:00 2001 From: Christian Scheb Date: Tue, 13 Mar 2018 19:29:40 +0100 Subject: [PATCH 06/12] Require factory classes only when they're needed --- src/rg/injektor/generators/FileGenerator.php | 53 +++++++++++-------- .../generators/FactoryGeneratorTest.php | 35 ++++++++---- 2 files changed, 56 insertions(+), 32 deletions(-) diff --git a/src/rg/injektor/generators/FileGenerator.php b/src/rg/injektor/generators/FileGenerator.php index d04922e..0584cd9 100644 --- a/src/rg/injektor/generators/FileGenerator.php +++ b/src/rg/injektor/generators/FileGenerator.php @@ -41,11 +41,6 @@ class FileGenerator { */ private $constructorArgumentStringParts = array(); - /** - * @var array - */ - private $usedFactories = array(); - /** * @var array */ @@ -106,6 +101,7 @@ public function getGeneratedFile() { $createInstanceMethod = new \rg\injektor\generators\CreateInstanceMethod(); $arguments = array(); + $injectionPropertiesRequireOnce = ''; $constructorMethodReflection = null; if ($this->dic->isSingleton($classReflection)) { @@ -131,10 +127,10 @@ public function getGeneratedFile() { $fullClassNameRefection = new \ReflectionClass($this->fullClassName); $providerClassName = $this->dic->getProviderClassName($classConfig, $fullClassNameRefection, null); if ($providerClassName && $providerClassName->getClassName()) { - $argumentFactory = $this->dic->getFullFactoryClassName($providerClassName->getClassName()); + $providerFactory = $this->dic->getFullFactoryClassName($providerClassName->getClassName()); $this->factoryGenerator->processFileForClass($providerClassName->getClassName()); - $createInstanceBody .= '$instance = \\' . $argumentFactory . '::getInstance(array())->get();' . PHP_EOL; - $this->usedFactories[] = $argumentFactory; + $createInstanceBody .= $this->requireOnceFactoryClass($providerFactory) . PHP_EOL; + $createInstanceBody .= '$instance = \\' . $providerFactory . '::getInstance(array())->get();' . PHP_EOL; } else { // constructor method arguments @@ -166,7 +162,7 @@ public function getGeneratedFile() { $this->factoryGenerator->processFileForClass($injectionParameter->getClassName()); } if ($injectionParameter->getFactoryName()) { - $this->usedFactories[] = $injectionParameter->getFactoryName(); + $createInstanceBody .= ' ' . $this->requireOnceFactoryClass($injectionParameter->getFactoryName()) . PHP_EOL; } $createInstanceBody .= ' ' . $injectionParameter->getProcessingBody(); } catch (\Exception $e) { @@ -193,7 +189,7 @@ public function getGeneratedFile() { $this->factoryGenerator->processFileForClass($injectionParameter->getClassName()); } if ($injectionParameter->getFactoryName()) { - $this->usedFactories[] = $injectionParameter->getFactoryName(); + $createInstanceBody .= ' ' . $this->requireOnceFactoryClass($injectionParameter->getFactoryName()) . PHP_EOL; } $createInstanceBody .= ' ' . $injectionParameter->getProcessingBody(); } catch (\Exception $e) { @@ -220,7 +216,7 @@ public function getGeneratedFile() { $this->factoryGenerator->processFileForClass($injectionParameter->getClassName()); } if ($injectionParameter->getFactoryName()) { - $this->usedFactories[] = $injectionParameter->getFactoryName(); + $createInstanceBody .= ' ' . $this->requireOnceFactoryClass($injectionParameter->getFactoryName()) . PHP_EOL; } $createInstanceBody .= ' ' . $injectionParameter->getProcessingBody(); } catch (\Exception $e) { @@ -232,8 +228,7 @@ public function getGeneratedFile() { } // Property injection - $this->injectProperties($classConfig, $classReflection); - + $injectionPropertiesRequireOnce = $this->injectProperties($classConfig, $classReflection); if (count($this->injectableProperties) > 0) { $proxyName = $this->dic->getProxyClassName($this->fullClassName); if ($this->dic->isSingleton($classReflection)) { @@ -262,6 +257,7 @@ public function getGeneratedFile() { } foreach ($this->injectableArguments as $injectableArgument) { + $createInstanceBody .= $injectionPropertiesRequireOnce; $createInstanceBody .= '$instance->propertyInjection' . $injectableArgument->getName() . '();' . PHP_EOL; } @@ -327,12 +323,6 @@ public function getGeneratedFile() { // Generate File $file->setNamespace('rg\injektor\generated'); - $this->usedFactories = array_unique($this->usedFactories); - foreach ($this->usedFactories as &$usedFactory) { - $usedFactory = str_replace('rg\injektor\generated\\', '', $usedFactory); - $usedFactory = $usedFactory . '.php'; - } - $file->setRequiredFiles($this->usedFactories); $file->setClass($factoryClass); $file->setFilename($this->factoryPath . DIRECTORY_SEPARATOR . $factoryName . '.php'); @@ -350,8 +340,11 @@ public function getGeneratedFile() { /** * @param array $classConfig * @param \ReflectionClass $classReflection + * + * @return string */ private function injectProperties(array $classConfig, \ReflectionClass $classReflection) { + $requireFactoryStatements = ''; try { $this->injectableProperties = $this->dic->getInjectableProperties($classReflection); foreach ($this->injectableProperties as $key => $injectableProperty) { @@ -371,7 +364,7 @@ private function injectProperties(array $classConfig, \ReflectionClass $classRef $this->factoryGenerator->processFileForClass($injectionProperty->getClassName()); } if ($injectionProperty->getFactoryName()) { - $this->usedFactories[] = $injectionProperty->getFactoryName(); + $requireFactoryStatements .= $this->requireOnceFactoryClass($injectionProperty->getFactoryName()) . PHP_EOL; } $this->injectableArguments[] = $injectionProperty; } catch (\Exception $e) { @@ -380,6 +373,8 @@ private function injectProperties(array $classConfig, \ReflectionClass $classRef } } catch (\Exception $e) { } + + return $requireFactoryStatements; } protected function getFactoryMethod(\ReflectionMethod $method, $classConfig) { @@ -418,7 +413,7 @@ protected function getFactoryMethod(\ReflectionMethod $method, $classConfig) { $this->factoryGenerator->processFileForClass($injectionParameter->getClassName()); } if ($injectionParameter->getFactoryName()) { - $this->usedFactories[] = $injectionParameter->getFactoryName(); + $body .= ' ' . $this->requireOnceFactoryClass($injectionParameter->getFactoryName()) . PHP_EOL; } $body .= ' ' . $injectionParameter->getProcessingBody(); } catch (\Exception $e) { @@ -444,7 +439,7 @@ protected function getFactoryMethod(\ReflectionMethod $method, $classConfig) { $this->factoryGenerator->processFileForClass($injectionParameter->getClassName()); } if ($injectionParameter->getFactoryName()) { - $this->usedFactories[] = $injectionParameter->getFactoryName(); + $body .= ' ' . $this->requireOnceFactoryClass($injectionParameter->getFactoryName()) . PHP_EOL; } $body .= ' ' . $injectionParameter->getProcessingBody(); } catch (\Exception $e) { @@ -470,7 +465,7 @@ protected function getFactoryMethod(\ReflectionMethod $method, $classConfig) { $this->factoryGenerator->processFileForClass($injectionParameter->getClassName()); } if ($injectionParameter->getFactoryName()) { - $this->usedFactories[] = $injectionParameter->getFactoryName(); + $body .= ' ' . $this->requireOnceFactoryClass($injectionParameter->getFactoryName()) . PHP_EOL; } $body .= ' ' . $injectionParameter->getProcessingBody(); } catch (\Exception $e) { @@ -502,4 +497,16 @@ private function createProxyClass($proxyName) { } return $proxyClass; } + + /** + * @param string $factoryClassName + * + * @return string + */ + private function requireOnceFactoryClass($factoryClassName) { + $factoryClassName = str_replace('rg\injektor\generated\\', '', $factoryClassName); + $factoryClassName = $factoryClassName . '.php'; + + return 'require_once \'' . $factoryClassName . '\';'; + } } diff --git a/test/rg/injektor/generators/FactoryGeneratorTest.php b/test/rg/injektor/generators/FactoryGeneratorTest.php index dc1467f..ae97123 100644 --- a/test/rg/injektor/generators/FactoryGeneratorTest.php +++ b/test/rg/injektor/generators/FactoryGeneratorTest.php @@ -78,8 +78,6 @@ public static function getInstance(array \$parameters = []) namespace rg\\injektor\\generated; -require_once 'rg_injektor_generators_FGTestClassSimpleFactory.php'; - class rg_injektor_generators_FGTestClassFourProxy extends \\rg\injektor\generators\\FGTestClassFour { @@ -106,14 +104,17 @@ public static function getInstance(array \$parameters = []) \$i = 0; if (!\$parameters) { + require_once 'rg_injektor_generators_FGTestClassSimpleFactory.php'; \$simple = \\rg\injektor\generated\\rg_injektor_generators_FGTestClassSimpleFactory::getInstance(array ( )); } else if (array_key_exists(0, \$parameters)) { + require_once 'rg_injektor_generators_FGTestClassSimpleFactory.php'; \$simple = array_key_exists(\$i, \$parameters) ? \$parameters[\$i] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassSimpleFactory::getInstance(array ( )); \$i++; } else { + require_once 'rg_injektor_generators_FGTestClassSimpleFactory.php'; \$simple = array_key_exists('simple', \$parameters) ? \$parameters['simple'] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassSimpleFactory::getInstance(array ( )); } @@ -121,6 +122,7 @@ public static function getInstance(array \$parameters = []) \$instance = rg_injektor_generators_FGTestClassFourProxy::getInstance(\$simple); \$singletonKey = serialize(\$parameters) . "#" . getmypid(); self::\$instance[\$singletonKey] = \$instance; + require_once 'rg_injektor_generators_FGTestClassSimpleFactory.php'; \$instance->propertyInjectioninjectedProperty(); return \$instance; } @@ -129,14 +131,17 @@ public static function callGetInstance(\$object, array \$parameters = []) { \$i = 0; if (!\$parameters) { + require_once 'rg_injektor_generators_FGTestClassSimpleFactory.php'; \$simple = \\rg\injektor\generated\\rg_injektor_generators_FGTestClassSimpleFactory::getInstance(array ( )); } else if (array_key_exists(0, \$parameters)) { + require_once 'rg_injektor_generators_FGTestClassSimpleFactory.php'; \$simple = array_key_exists(\$i, \$parameters) ? \$parameters[\$i] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassSimpleFactory::getInstance(array ( )); \$i++; } else { + require_once 'rg_injektor_generators_FGTestClassSimpleFactory.php'; \$simple = array_key_exists('simple', \$parameters) ? \$parameters['simple'] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassSimpleFactory::getInstance(array ( )); } @@ -157,8 +162,6 @@ public static function callGetInstance(\$object, array \$parameters = []) namespace rg\\injektor\\generated; -require_once 'rg_injektor_generators_FGTestClassFourFactory.php'; - class rg_injektor_generators_FGTestClassThreeFactory { @@ -167,16 +170,19 @@ public static function getInstance(array \$parameters = []) \$i = 0; if (!\$parameters) { \$foo = 'foo'; + require_once 'rg_injektor_generators_FGTestClassFourFactory.php'; \$four = \\rg\injektor\generated\\rg_injektor_generators_FGTestClassFourFactory::getInstance(array ( )); } else if (array_key_exists(0, \$parameters)) { \$foo = array_key_exists(\$i, \$parameters) ? \$parameters[\$i] : 'foo'; \$i++; + require_once 'rg_injektor_generators_FGTestClassFourFactory.php'; \$four = array_key_exists(\$i, \$parameters) ? \$parameters[\$i] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassFourFactory::getInstance(array ( )); \$i++; } else { \$foo = array_key_exists('foo', \$parameters) ? \$parameters['foo'] : 'foo'; + require_once 'rg_injektor_generators_FGTestClassFourFactory.php'; \$four = array_key_exists('four', \$parameters) ? \$parameters['four'] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassFourFactory::getInstance(array ( )); } @@ -206,8 +212,6 @@ public static function callGetSomething(\$object) namespace rg\\injektor\\generated; -require_once 'rg_injektor_generators_FGTestClassThreeFactory.php'; - class rg_injektor_generators_FGTestClassTwoFactory { @@ -215,14 +219,17 @@ public static function getInstance(array \$parameters = []) { \$i = 0; if (!\$parameters) { + require_once 'rg_injektor_generators_FGTestClassThreeFactory.php'; \$three = \\rg\injektor\generated\\rg_injektor_generators_FGTestClassThreeFactory::getInstance(array ( )); } else if (array_key_exists(0, \$parameters)) { + require_once 'rg_injektor_generators_FGTestClassThreeFactory.php'; \$three = array_key_exists(\$i, \$parameters) ? \$parameters[\$i] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassThreeFactory::getInstance(array ( )); \$i++; } else { + require_once 'rg_injektor_generators_FGTestClassThreeFactory.php'; \$three = array_key_exists('three', \$parameters) ? \$parameters['three'] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassThreeFactory::getInstance(array ( )); } @@ -251,9 +258,6 @@ public static function callGetSomething(\$object) namespace rg\\injektor\\generated; -require_once 'rg_injektor_generators_FGTestClassTwoFactory.php'; -require_once 'rg_injektor_generators_FGTestClassThreeFactory.php'; - class rg_injektor_generators_FGTestClassOneProxy extends \\rg\\injektor\\generators\\FGTestClassOne { @@ -280,20 +284,26 @@ public static function getInstance(array \$parameters = []) \$i = 0; if (!\$parameters) { + require_once 'rg_injektor_generators_FGTestClassTwoFactory.php'; \$two = \\rg\injektor\generated\\rg_injektor_generators_FGTestClassTwoFactory::getInstance(array ( )); + require_once 'rg_injektor_generators_FGTestClassThreeFactory.php'; \$three = \\rg\injektor\generated\\rg_injektor_generators_FGTestClassThreeFactory::getInstance(array ( )); } else if (array_key_exists(0, \$parameters)) { + require_once 'rg_injektor_generators_FGTestClassTwoFactory.php'; \$two = array_key_exists(\$i, \$parameters) ? \$parameters[\$i] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassTwoFactory::getInstance(array ( )); \$i++; + require_once 'rg_injektor_generators_FGTestClassThreeFactory.php'; \$three = array_key_exists(\$i, \$parameters) ? \$parameters[\$i] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassThreeFactory::getInstance(array ( )); \$i++; } else { + require_once 'rg_injektor_generators_FGTestClassTwoFactory.php'; \$two = array_key_exists('two', \$parameters) ? \$parameters['two'] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassTwoFactory::getInstance(array ( )); + require_once 'rg_injektor_generators_FGTestClassThreeFactory.php'; \$three = array_key_exists('three', \$parameters) ? \$parameters['three'] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassThreeFactory::getInstance(array ( )); } @@ -301,6 +311,7 @@ public static function getInstance(array \$parameters = []) \$instance = new rg_injektor_generators_FGTestClassOneProxy(\$two, \$three); \$singletonKey = serialize(\$parameters) . "#" . getmypid(); self::\$instance[\$singletonKey] = \$instance; + require_once 'rg_injektor_generators_FGTestClassThreeFactory.php'; \$instance->propertyInjectionfour(); return \$instance; } @@ -318,20 +329,26 @@ public static function callGetSomething(\$object, array \$parameters = []) { \$i = 0; if (!\$parameters) { + require_once 'rg_injektor_generators_FGTestClassTwoFactory.php'; \$two = \\rg\injektor\generated\\rg_injektor_generators_FGTestClassTwoFactory::getInstance(array ( )); + require_once 'rg_injektor_generators_FGTestClassThreeFactory.php'; \$three = \\rg\injektor\generated\\rg_injektor_generators_FGTestClassThreeFactory::getInstance(array ( )); } else if (array_key_exists(0, \$parameters)) { + require_once 'rg_injektor_generators_FGTestClassTwoFactory.php'; \$two = array_key_exists(\$i, \$parameters) ? \$parameters[\$i] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassTwoFactory::getInstance(array ( )); \$i++; + require_once 'rg_injektor_generators_FGTestClassThreeFactory.php'; \$three = array_key_exists(\$i, \$parameters) ? \$parameters[\$i] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassThreeFactory::getInstance(array ( )); \$i++; } else { + require_once 'rg_injektor_generators_FGTestClassTwoFactory.php'; \$two = array_key_exists('two', \$parameters) ? \$parameters['two'] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassTwoFactory::getInstance(array ( )); + require_once 'rg_injektor_generators_FGTestClassThreeFactory.php'; \$three = array_key_exists('three', \$parameters) ? \$parameters['three'] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassThreeFactory::getInstance(array ( )); } From 963be01a7db589b4cdc5e3e16eaee76392565579 Mon Sep 17 00:00:00 2001 From: Christian Scheb Date: Tue, 13 Mar 2018 19:48:11 +0100 Subject: [PATCH 07/12] Lazy loading config --- src/rg/injektor/Configuration.php | 45 ++++++++++++++++++- .../injektor/DependencyInjectionContainer.php | 34 +++++++++++++- src/rg/injektor/generators/FileGenerator.php | 2 +- .../DependencyInjectionContainerTest.php | 8 ++-- 4 files changed, 80 insertions(+), 9 deletions(-) diff --git a/src/rg/injektor/Configuration.php b/src/rg/injektor/Configuration.php index 701450a..99bdfa3 100644 --- a/src/rg/injektor/Configuration.php +++ b/src/rg/injektor/Configuration.php @@ -24,15 +24,36 @@ class Configuration { */ private $factoryPath; + /** + * @var bool + */ + private $lazyLoading; + + /** + * @var bool + */ + private $lazyServices; + + /** + * @var bool + */ + private $lazySingletons; + /** * @param string $configurationFilePath * @param string $factoryPath + * @param bool $lazyLoading + * @param bool $lazyServices + * @param bool $lazySingletons */ - public function __construct($configurationFilePath = null, $factoryPath = '') { + public function __construct($configurationFilePath = null, $factoryPath = '', $lazyLoading = false, $lazyServices = false, $lazySingletons = false) { if ($configurationFilePath) { $this->addConfigFile($configurationFilePath); } $this->factoryPath = $factoryPath; + $this->lazyLoading = $lazyLoading; + $this->lazyServices = $lazyServices; + $this->lazySingletons = $lazySingletons; } /** @@ -96,4 +117,24 @@ public function getFactoryPath() { return $this->factoryPath; } -} \ No newline at end of file + /** + * @return bool + */ + public function isLazyLoading() { + return $this->lazyLoading; + } + + /** + * @return bool + */ + public function isLazyServices() { + return $this->lazyServices; + } + + /** + * @return bool + */ + public function isLazySingletons() { + return $this->lazySingletons; + } +} diff --git a/src/rg/injektor/DependencyInjectionContainer.php b/src/rg/injektor/DependencyInjectionContainer.php index 34d27d0..3a46771 100644 --- a/src/rg/injektor/DependencyInjectionContainer.php +++ b/src/rg/injektor/DependencyInjectionContainer.php @@ -248,7 +248,7 @@ private function createNewInstance(array $classConfig, \ReflectionClass $classRe return $classReflection->newInstanceArgs($constructorArguments ? $constructorArguments : []); }; - if ($this->supportsLazyLoading && $this->isConfiguredAsLazy($classConfig, $classReflection)) { + if ($this->supportsLazyLoading && $this->config->isLazyLoading() && $this->isConfiguredAsLazy($classConfig, $classReflection)) { return $this->wrapInstanceWithLazyProxy($classReflection->getName(), $instanceConstructor); } else { return $instanceConstructor(); @@ -475,7 +475,7 @@ public function getProvidedConfiguredClass($classConfig, \ReflectionClass $class return $this->getRealClassInstanceFromProvider($namedAnnotation->getClassName(), $classReflection->name, array_merge($namedAnnotation->getParameters(), $additionalArgumentsForProvider)); }; - if ($this->supportsLazyLoading && $this->isConfiguredAsLazy($classConfig, $classReflection)) { + if ($this->supportsLazyLoading && $this->config->isLazyLoading() && $this->isConfiguredAsLazy($classConfig, $classReflection)) { return $this->wrapInstanceWithLazyProxy($classReflection->name, $instanceConstructor); } else { return $instanceConstructor(); @@ -665,6 +665,21 @@ public function isConfiguredAsService(array $classConfig, \ReflectionClass $clas * @return bool */ public function isConfiguredAsLazy(array $classConfig, \ReflectionClass $classReflection) { + // Force no lazy loading + if ($this->isConfiguredAsNoLazy($classConfig, $classReflection)) { + return false; + } + + // Lazy services + if ($this->config->isLazyServices() && $this->isConfiguredAsService($classConfig, $classReflection)) { + return true; + } + + // Lazy singletons + if ($this->config->isLazySingletons() && $this->isConfiguredAsSingleton($classConfig, $classReflection)) { + return true; + } + if (isset($classConfig['lazy'])) { return (bool) $classConfig['lazy']; } @@ -674,6 +689,21 @@ public function isConfiguredAsLazy(array $classConfig, \ReflectionClass $classRe return strpos($classComment, '@lazy') !== false; } + /** + * @param array $classConfig + * @param \ReflectionClass $classReflection + * @return bool + */ + public function isConfiguredAsNoLazy(array $classConfig, \ReflectionClass $classReflection) { + if (isset($classConfig['noLazy'])) { + return (bool) $classConfig['noLazy']; + } + + $classComment = $classReflection->getDocComment(); + + return strpos($classComment, '@noLazy') !== false; + } + /** * @param object $object * @param string $methodName diff --git a/src/rg/injektor/generators/FileGenerator.php b/src/rg/injektor/generators/FileGenerator.php index 0584cd9..0a48a05 100644 --- a/src/rg/injektor/generators/FileGenerator.php +++ b/src/rg/injektor/generators/FileGenerator.php @@ -114,7 +114,7 @@ public function getGeneratedFile() { $isSingleton = $this->dic->isConfiguredAsSingleton($classConfig, $classReflection); $isService = $this->dic->isConfiguredAsService($classConfig, $classReflection); - $isLazy = $this->dic->supportsLazyLoading() && $this->dic->isConfiguredAsLazy($classConfig, $classReflection); + $isLazy = $this->dic->supportsLazyLoading() && $this->config->isLazyLoading() && $this->dic->isConfiguredAsLazy($classConfig, $classReflection); $createInstanceBody = '$i = 0;' . PHP_EOL; if ($isSingleton || $isService) { diff --git a/test/rg/injektor/DependencyInjectionContainerTest.php b/test/rg/injektor/DependencyInjectionContainerTest.php index d1f4e10..9db66f6 100644 --- a/test/rg/injektor/DependencyInjectionContainerTest.php +++ b/test/rg/injektor/DependencyInjectionContainerTest.php @@ -212,7 +212,7 @@ public function testGetInstanceOfAnnotatedService() { } public function testGetInstanceOfLazy() { - $config = new Configuration(null, __DIR__ . '/_factories'); + $config = new Configuration(null, __DIR__ . '/_factories', true); $config->setClassConfig('rg\injektor\DICTestLazy', [ 'lazy' => true @@ -227,7 +227,7 @@ public function testGetInstanceOfLazy() { } public function testGetInstanceOfAnnotatedLazy() { - $config = new Configuration(null, __DIR__ . '/_factories'); + $config = new Configuration(null, __DIR__ . '/_factories', true); $config->setClassConfig('rg\injektor\DICTestAnnotatedLazy', []); $dic = $this->getContainer($config); @@ -240,7 +240,7 @@ public function testGetInstanceOfAnnotatedLazy() { } public function testGetInstanceOfLazyService() { - $config = new Configuration(null, __DIR__ . '/_factories'); + $config = new Configuration(null, __DIR__ . '/_factories', true); $config->setClassConfig('rg\injektor\DICTestLazyService', [ 'lazy' => true, @@ -259,7 +259,7 @@ public function testGetInstanceOfLazyService() { } public function testGetInstanceOfAnnotatedLazyService() { - $config = new Configuration(null, __DIR__ . '/_factories'); + $config = new Configuration(null, __DIR__ . '/_factories', true); $config->setClassConfig('rg\injektor\DICTestAnnotatedLazyService', []); $dic = $this->getContainer($config); From 48638ad4ef27c1873530ee4ac3333384eed54380 Mon Sep 17 00:00:00 2001 From: Christian Scheb Date: Wed, 14 Mar 2018 17:37:56 +0100 Subject: [PATCH 08/12] Property injection on lazy-loaded instances --- .../injektor/DependencyInjectionContainer.php | 35 +++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/src/rg/injektor/DependencyInjectionContainer.php b/src/rg/injektor/DependencyInjectionContainer.php index 3a46771..21ab232 100644 --- a/src/rg/injektor/DependencyInjectionContainer.php +++ b/src/rg/injektor/DependencyInjectionContainer.php @@ -212,10 +212,24 @@ public function getInstanceOfClass($fullClassName, array $constructorArguments = $instance = $classReflection->getMethod('getInstance')->invokeArgs(null, $constructorArguments); } else { $constructorArguments = $this->getConstructorArguments($classReflection, $classConfig, $constructorArguments); - $instance = $this->createNewInstance($classConfig, $classReflection, $constructorArguments); - } + $instanceConstructor = function () use ($classReflection, $constructorArguments, $isConfiguredAsSingleton, $isConfiguredAsService, $singletonKey, $fullClassName) { + $instance = $classReflection->newInstanceArgs($constructorArguments ? $constructorArguments : []); - $this->log('Created instance [' . spl_object_hash($instance) . '] of class [' . get_class($instance) . ']'); + if ($isConfiguredAsSingleton) { + $this->log('Added singleton instance [' . spl_object_hash($instance) . '] of class [' . get_class($instance) . '], Singleton Key: [' . $singletonKey . ']'); + $this->instances[$singletonKey] = $instance; + } + if ($isConfiguredAsService) { + $this->log('Added service instance [' . spl_object_hash($instance) . '] of class [' . $fullClassName . ']'); + $this->instances[$fullClassName] = $instance; + } + + $instance = $this->injectProperties($classReflection, $instance); + + return $instance; + }; + $instance = $this->createNewInstance($classConfig, $classReflection, $instanceConstructor); + } if ($isConfiguredAsSingleton) { $this->log('Added singleton instance [' . spl_object_hash($instance) . '] of class [' . get_class($instance) . '], Singleton Key: [' . $singletonKey . ']'); @@ -228,6 +242,8 @@ public function getInstanceOfClass($fullClassName, array $constructorArguments = $instance = $this->injectProperties($classReflection, $instance); + $this->log('Created instance [' . spl_object_hash($instance) . '] of class [' . get_class($instance) . ']'); + if ($this->iterationDepth > 0) { $this->iterationDepth--; } @@ -238,16 +254,11 @@ public function getInstanceOfClass($fullClassName, array $constructorArguments = /** * @param array $classConfig * @param \ReflectionClass $classReflection - * @param array $constructorArguments + * @param callable $instanceConstructor * * @return object */ - private function createNewInstance(array $classConfig, \ReflectionClass $classReflection, $constructorArguments) - { - $instanceConstructor = function () use ($classReflection, $constructorArguments) { - return $classReflection->newInstanceArgs($constructorArguments ? $constructorArguments : []); - }; - + private function createNewInstance(array $classConfig, \ReflectionClass $classReflection, $instanceConstructor) { if ($this->supportsLazyLoading && $this->config->isLazyLoading() && $this->isConfiguredAsLazy($classConfig, $classReflection)) { return $this->wrapInstanceWithLazyProxy($classReflection->getName(), $instanceConstructor); } else { @@ -347,6 +358,10 @@ private function getDefaultArguments($classConfig, $defaultConstructorArguments) * @throws InjectionException */ private function injectProperties($classReflection, $instance) { + if ($instance instanceof \ProxyManager\Proxy\LazyLoadingInterface) { + return $instance; // Not inject into lazy proxies + } + $properties = $this->getInjectableProperties($classReflection); foreach ($properties as $property) { $this->injectProperty($property, $instance); From 2b2620007550053925797b17b41e37ca9140a48f Mon Sep 17 00:00:00 2001 From: Christian Scheb Date: Fri, 16 Mar 2018 12:02:53 +0100 Subject: [PATCH 09/12] Revert "Require factory classes only when they're needed" --- src/rg/injektor/generators/FileGenerator.php | 53 ++++++++----------- .../generators/FactoryGeneratorTest.php | 35 ++++-------- 2 files changed, 32 insertions(+), 56 deletions(-) diff --git a/src/rg/injektor/generators/FileGenerator.php b/src/rg/injektor/generators/FileGenerator.php index 0a48a05..fd43292 100644 --- a/src/rg/injektor/generators/FileGenerator.php +++ b/src/rg/injektor/generators/FileGenerator.php @@ -41,6 +41,11 @@ class FileGenerator { */ private $constructorArgumentStringParts = array(); + /** + * @var array + */ + private $usedFactories = array(); + /** * @var array */ @@ -101,7 +106,6 @@ public function getGeneratedFile() { $createInstanceMethod = new \rg\injektor\generators\CreateInstanceMethod(); $arguments = array(); - $injectionPropertiesRequireOnce = ''; $constructorMethodReflection = null; if ($this->dic->isSingleton($classReflection)) { @@ -127,10 +131,10 @@ public function getGeneratedFile() { $fullClassNameRefection = new \ReflectionClass($this->fullClassName); $providerClassName = $this->dic->getProviderClassName($classConfig, $fullClassNameRefection, null); if ($providerClassName && $providerClassName->getClassName()) { - $providerFactory = $this->dic->getFullFactoryClassName($providerClassName->getClassName()); + $argumentFactory = $this->dic->getFullFactoryClassName($providerClassName->getClassName()); $this->factoryGenerator->processFileForClass($providerClassName->getClassName()); - $createInstanceBody .= $this->requireOnceFactoryClass($providerFactory) . PHP_EOL; - $createInstanceBody .= '$instance = \\' . $providerFactory . '::getInstance(array())->get();' . PHP_EOL; + $createInstanceBody .= '$instance = \\' . $argumentFactory . '::getInstance(array())->get();' . PHP_EOL; + $this->usedFactories[] = $argumentFactory; } else { // constructor method arguments @@ -162,7 +166,7 @@ public function getGeneratedFile() { $this->factoryGenerator->processFileForClass($injectionParameter->getClassName()); } if ($injectionParameter->getFactoryName()) { - $createInstanceBody .= ' ' . $this->requireOnceFactoryClass($injectionParameter->getFactoryName()) . PHP_EOL; + $this->usedFactories[] = $injectionParameter->getFactoryName(); } $createInstanceBody .= ' ' . $injectionParameter->getProcessingBody(); } catch (\Exception $e) { @@ -189,7 +193,7 @@ public function getGeneratedFile() { $this->factoryGenerator->processFileForClass($injectionParameter->getClassName()); } if ($injectionParameter->getFactoryName()) { - $createInstanceBody .= ' ' . $this->requireOnceFactoryClass($injectionParameter->getFactoryName()) . PHP_EOL; + $this->usedFactories[] = $injectionParameter->getFactoryName(); } $createInstanceBody .= ' ' . $injectionParameter->getProcessingBody(); } catch (\Exception $e) { @@ -216,7 +220,7 @@ public function getGeneratedFile() { $this->factoryGenerator->processFileForClass($injectionParameter->getClassName()); } if ($injectionParameter->getFactoryName()) { - $createInstanceBody .= ' ' . $this->requireOnceFactoryClass($injectionParameter->getFactoryName()) . PHP_EOL; + $this->usedFactories[] = $injectionParameter->getFactoryName(); } $createInstanceBody .= ' ' . $injectionParameter->getProcessingBody(); } catch (\Exception $e) { @@ -228,7 +232,8 @@ public function getGeneratedFile() { } // Property injection - $injectionPropertiesRequireOnce = $this->injectProperties($classConfig, $classReflection); + $this->injectProperties($classConfig, $classReflection); + if (count($this->injectableProperties) > 0) { $proxyName = $this->dic->getProxyClassName($this->fullClassName); if ($this->dic->isSingleton($classReflection)) { @@ -257,7 +262,6 @@ public function getGeneratedFile() { } foreach ($this->injectableArguments as $injectableArgument) { - $createInstanceBody .= $injectionPropertiesRequireOnce; $createInstanceBody .= '$instance->propertyInjection' . $injectableArgument->getName() . '();' . PHP_EOL; } @@ -323,6 +327,12 @@ public function getGeneratedFile() { // Generate File $file->setNamespace('rg\injektor\generated'); + $this->usedFactories = array_unique($this->usedFactories); + foreach ($this->usedFactories as &$usedFactory) { + $usedFactory = str_replace('rg\injektor\generated\\', '', $usedFactory); + $usedFactory = $usedFactory . '.php'; + } + $file->setRequiredFiles($this->usedFactories); $file->setClass($factoryClass); $file->setFilename($this->factoryPath . DIRECTORY_SEPARATOR . $factoryName . '.php'); @@ -340,11 +350,8 @@ public function getGeneratedFile() { /** * @param array $classConfig * @param \ReflectionClass $classReflection - * - * @return string */ private function injectProperties(array $classConfig, \ReflectionClass $classReflection) { - $requireFactoryStatements = ''; try { $this->injectableProperties = $this->dic->getInjectableProperties($classReflection); foreach ($this->injectableProperties as $key => $injectableProperty) { @@ -364,7 +371,7 @@ private function injectProperties(array $classConfig, \ReflectionClass $classRef $this->factoryGenerator->processFileForClass($injectionProperty->getClassName()); } if ($injectionProperty->getFactoryName()) { - $requireFactoryStatements .= $this->requireOnceFactoryClass($injectionProperty->getFactoryName()) . PHP_EOL; + $this->usedFactories[] = $injectionProperty->getFactoryName(); } $this->injectableArguments[] = $injectionProperty; } catch (\Exception $e) { @@ -373,8 +380,6 @@ private function injectProperties(array $classConfig, \ReflectionClass $classRef } } catch (\Exception $e) { } - - return $requireFactoryStatements; } protected function getFactoryMethod(\ReflectionMethod $method, $classConfig) { @@ -413,7 +418,7 @@ protected function getFactoryMethod(\ReflectionMethod $method, $classConfig) { $this->factoryGenerator->processFileForClass($injectionParameter->getClassName()); } if ($injectionParameter->getFactoryName()) { - $body .= ' ' . $this->requireOnceFactoryClass($injectionParameter->getFactoryName()) . PHP_EOL; + $this->usedFactories[] = $injectionParameter->getFactoryName(); } $body .= ' ' . $injectionParameter->getProcessingBody(); } catch (\Exception $e) { @@ -439,7 +444,7 @@ protected function getFactoryMethod(\ReflectionMethod $method, $classConfig) { $this->factoryGenerator->processFileForClass($injectionParameter->getClassName()); } if ($injectionParameter->getFactoryName()) { - $body .= ' ' . $this->requireOnceFactoryClass($injectionParameter->getFactoryName()) . PHP_EOL; + $this->usedFactories[] = $injectionParameter->getFactoryName(); } $body .= ' ' . $injectionParameter->getProcessingBody(); } catch (\Exception $e) { @@ -465,7 +470,7 @@ protected function getFactoryMethod(\ReflectionMethod $method, $classConfig) { $this->factoryGenerator->processFileForClass($injectionParameter->getClassName()); } if ($injectionParameter->getFactoryName()) { - $body .= ' ' . $this->requireOnceFactoryClass($injectionParameter->getFactoryName()) . PHP_EOL; + $this->usedFactories[] = $injectionParameter->getFactoryName(); } $body .= ' ' . $injectionParameter->getProcessingBody(); } catch (\Exception $e) { @@ -497,16 +502,4 @@ private function createProxyClass($proxyName) { } return $proxyClass; } - - /** - * @param string $factoryClassName - * - * @return string - */ - private function requireOnceFactoryClass($factoryClassName) { - $factoryClassName = str_replace('rg\injektor\generated\\', '', $factoryClassName); - $factoryClassName = $factoryClassName . '.php'; - - return 'require_once \'' . $factoryClassName . '\';'; - } } diff --git a/test/rg/injektor/generators/FactoryGeneratorTest.php b/test/rg/injektor/generators/FactoryGeneratorTest.php index ae97123..dc1467f 100644 --- a/test/rg/injektor/generators/FactoryGeneratorTest.php +++ b/test/rg/injektor/generators/FactoryGeneratorTest.php @@ -78,6 +78,8 @@ public static function getInstance(array \$parameters = []) namespace rg\\injektor\\generated; +require_once 'rg_injektor_generators_FGTestClassSimpleFactory.php'; + class rg_injektor_generators_FGTestClassFourProxy extends \\rg\injektor\generators\\FGTestClassFour { @@ -104,17 +106,14 @@ public static function getInstance(array \$parameters = []) \$i = 0; if (!\$parameters) { - require_once 'rg_injektor_generators_FGTestClassSimpleFactory.php'; \$simple = \\rg\injektor\generated\\rg_injektor_generators_FGTestClassSimpleFactory::getInstance(array ( )); } else if (array_key_exists(0, \$parameters)) { - require_once 'rg_injektor_generators_FGTestClassSimpleFactory.php'; \$simple = array_key_exists(\$i, \$parameters) ? \$parameters[\$i] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassSimpleFactory::getInstance(array ( )); \$i++; } else { - require_once 'rg_injektor_generators_FGTestClassSimpleFactory.php'; \$simple = array_key_exists('simple', \$parameters) ? \$parameters['simple'] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassSimpleFactory::getInstance(array ( )); } @@ -122,7 +121,6 @@ public static function getInstance(array \$parameters = []) \$instance = rg_injektor_generators_FGTestClassFourProxy::getInstance(\$simple); \$singletonKey = serialize(\$parameters) . "#" . getmypid(); self::\$instance[\$singletonKey] = \$instance; - require_once 'rg_injektor_generators_FGTestClassSimpleFactory.php'; \$instance->propertyInjectioninjectedProperty(); return \$instance; } @@ -131,17 +129,14 @@ public static function callGetInstance(\$object, array \$parameters = []) { \$i = 0; if (!\$parameters) { - require_once 'rg_injektor_generators_FGTestClassSimpleFactory.php'; \$simple = \\rg\injektor\generated\\rg_injektor_generators_FGTestClassSimpleFactory::getInstance(array ( )); } else if (array_key_exists(0, \$parameters)) { - require_once 'rg_injektor_generators_FGTestClassSimpleFactory.php'; \$simple = array_key_exists(\$i, \$parameters) ? \$parameters[\$i] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassSimpleFactory::getInstance(array ( )); \$i++; } else { - require_once 'rg_injektor_generators_FGTestClassSimpleFactory.php'; \$simple = array_key_exists('simple', \$parameters) ? \$parameters['simple'] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassSimpleFactory::getInstance(array ( )); } @@ -162,6 +157,8 @@ public static function callGetInstance(\$object, array \$parameters = []) namespace rg\\injektor\\generated; +require_once 'rg_injektor_generators_FGTestClassFourFactory.php'; + class rg_injektor_generators_FGTestClassThreeFactory { @@ -170,19 +167,16 @@ public static function getInstance(array \$parameters = []) \$i = 0; if (!\$parameters) { \$foo = 'foo'; - require_once 'rg_injektor_generators_FGTestClassFourFactory.php'; \$four = \\rg\injektor\generated\\rg_injektor_generators_FGTestClassFourFactory::getInstance(array ( )); } else if (array_key_exists(0, \$parameters)) { \$foo = array_key_exists(\$i, \$parameters) ? \$parameters[\$i] : 'foo'; \$i++; - require_once 'rg_injektor_generators_FGTestClassFourFactory.php'; \$four = array_key_exists(\$i, \$parameters) ? \$parameters[\$i] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassFourFactory::getInstance(array ( )); \$i++; } else { \$foo = array_key_exists('foo', \$parameters) ? \$parameters['foo'] : 'foo'; - require_once 'rg_injektor_generators_FGTestClassFourFactory.php'; \$four = array_key_exists('four', \$parameters) ? \$parameters['four'] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassFourFactory::getInstance(array ( )); } @@ -212,6 +206,8 @@ public static function callGetSomething(\$object) namespace rg\\injektor\\generated; +require_once 'rg_injektor_generators_FGTestClassThreeFactory.php'; + class rg_injektor_generators_FGTestClassTwoFactory { @@ -219,17 +215,14 @@ public static function getInstance(array \$parameters = []) { \$i = 0; if (!\$parameters) { - require_once 'rg_injektor_generators_FGTestClassThreeFactory.php'; \$three = \\rg\injektor\generated\\rg_injektor_generators_FGTestClassThreeFactory::getInstance(array ( )); } else if (array_key_exists(0, \$parameters)) { - require_once 'rg_injektor_generators_FGTestClassThreeFactory.php'; \$three = array_key_exists(\$i, \$parameters) ? \$parameters[\$i] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassThreeFactory::getInstance(array ( )); \$i++; } else { - require_once 'rg_injektor_generators_FGTestClassThreeFactory.php'; \$three = array_key_exists('three', \$parameters) ? \$parameters['three'] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassThreeFactory::getInstance(array ( )); } @@ -258,6 +251,9 @@ public static function callGetSomething(\$object) namespace rg\\injektor\\generated; +require_once 'rg_injektor_generators_FGTestClassTwoFactory.php'; +require_once 'rg_injektor_generators_FGTestClassThreeFactory.php'; + class rg_injektor_generators_FGTestClassOneProxy extends \\rg\\injektor\\generators\\FGTestClassOne { @@ -284,26 +280,20 @@ public static function getInstance(array \$parameters = []) \$i = 0; if (!\$parameters) { - require_once 'rg_injektor_generators_FGTestClassTwoFactory.php'; \$two = \\rg\injektor\generated\\rg_injektor_generators_FGTestClassTwoFactory::getInstance(array ( )); - require_once 'rg_injektor_generators_FGTestClassThreeFactory.php'; \$three = \\rg\injektor\generated\\rg_injektor_generators_FGTestClassThreeFactory::getInstance(array ( )); } else if (array_key_exists(0, \$parameters)) { - require_once 'rg_injektor_generators_FGTestClassTwoFactory.php'; \$two = array_key_exists(\$i, \$parameters) ? \$parameters[\$i] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassTwoFactory::getInstance(array ( )); \$i++; - require_once 'rg_injektor_generators_FGTestClassThreeFactory.php'; \$three = array_key_exists(\$i, \$parameters) ? \$parameters[\$i] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassThreeFactory::getInstance(array ( )); \$i++; } else { - require_once 'rg_injektor_generators_FGTestClassTwoFactory.php'; \$two = array_key_exists('two', \$parameters) ? \$parameters['two'] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassTwoFactory::getInstance(array ( )); - require_once 'rg_injektor_generators_FGTestClassThreeFactory.php'; \$three = array_key_exists('three', \$parameters) ? \$parameters['three'] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassThreeFactory::getInstance(array ( )); } @@ -311,7 +301,6 @@ public static function getInstance(array \$parameters = []) \$instance = new rg_injektor_generators_FGTestClassOneProxy(\$two, \$three); \$singletonKey = serialize(\$parameters) . "#" . getmypid(); self::\$instance[\$singletonKey] = \$instance; - require_once 'rg_injektor_generators_FGTestClassThreeFactory.php'; \$instance->propertyInjectionfour(); return \$instance; } @@ -329,26 +318,20 @@ public static function callGetSomething(\$object, array \$parameters = []) { \$i = 0; if (!\$parameters) { - require_once 'rg_injektor_generators_FGTestClassTwoFactory.php'; \$two = \\rg\injektor\generated\\rg_injektor_generators_FGTestClassTwoFactory::getInstance(array ( )); - require_once 'rg_injektor_generators_FGTestClassThreeFactory.php'; \$three = \\rg\injektor\generated\\rg_injektor_generators_FGTestClassThreeFactory::getInstance(array ( )); } else if (array_key_exists(0, \$parameters)) { - require_once 'rg_injektor_generators_FGTestClassTwoFactory.php'; \$two = array_key_exists(\$i, \$parameters) ? \$parameters[\$i] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassTwoFactory::getInstance(array ( )); \$i++; - require_once 'rg_injektor_generators_FGTestClassThreeFactory.php'; \$three = array_key_exists(\$i, \$parameters) ? \$parameters[\$i] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassThreeFactory::getInstance(array ( )); \$i++; } else { - require_once 'rg_injektor_generators_FGTestClassTwoFactory.php'; \$two = array_key_exists('two', \$parameters) ? \$parameters['two'] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassTwoFactory::getInstance(array ( )); - require_once 'rg_injektor_generators_FGTestClassThreeFactory.php'; \$three = array_key_exists('three', \$parameters) ? \$parameters['three'] : \\rg\injektor\generated\\rg_injektor_generators_FGTestClassThreeFactory::getInstance(array ( )); } From 48cd1f3396e965a591e377fc512062e9c88833b7 Mon Sep 17 00:00:00 2001 From: Christian Scheb Date: Fri, 16 Mar 2018 14:49:33 +0100 Subject: [PATCH 10/12] More efficient dependency loading --- src/rg/injektor/generators/FileGenerator.php | 35 ++++++++++++++----- .../generators/LoadDependenciesMethod.php | 17 +++++++++ 2 files changed, 44 insertions(+), 8 deletions(-) create mode 100644 src/rg/injektor/generators/LoadDependenciesMethod.php diff --git a/src/rg/injektor/generators/FileGenerator.php b/src/rg/injektor/generators/FileGenerator.php index fd43292..756fad5 100644 --- a/src/rg/injektor/generators/FileGenerator.php +++ b/src/rg/injektor/generators/FileGenerator.php @@ -99,11 +99,14 @@ public function getGeneratedFile() { return null; } - $file = new Generator\FileGenerator(); - $factoryClass = new \rg\injektor\generators\FactoryClass($factoryName); $getInstanceMethod = new \rg\injektor\generators\GetInstanceMethod(); $createInstanceMethod = new \rg\injektor\generators\CreateInstanceMethod(); + $loadDependenciesMethod = new \rg\injektor\generators\LoadDependenciesMethod(); + + $file = new Generator\FileGenerator(); + $file->setNamespace('rg\injektor\generated'); + $file->setFilename($this->factoryPath . DIRECTORY_SEPARATOR . $factoryName . '.php'); $arguments = array(); @@ -120,7 +123,13 @@ public function getGeneratedFile() { $isService = $this->dic->isConfiguredAsService($classConfig, $classReflection); $isLazy = $this->dic->supportsLazyLoading() && $this->config->isLazyLoading() && $this->dic->isConfiguredAsLazy($classConfig, $classReflection); - $createInstanceBody = '$i = 0;' . PHP_EOL; + $createInstanceBody = ''; + + if ($isLazy) { + $createInstanceBody .= 'self::loadDependencies();' . PHP_EOL; + } + + $createInstanceBody .= '$i = 0;' . PHP_EOL; if ($isSingleton || $isService) { $defaultValue = new Generator\PropertyValueGenerator(array(), Generator\ValueGenerator::TYPE_ARRAY, Generator\ValueGenerator::OUTPUT_SINGLE_LINE); $property = new Generator\PropertyGenerator('instance', $defaultValue, Generator\PropertyGenerator::FLAG_PRIVATE); @@ -285,7 +294,7 @@ public function getGeneratedFile() { $getInstanceBody .= '$instance = ' . $lazyProxyClassName . '::staticProxyConstructor(' . PHP_EOL; $getInstanceBody .= ' function (&$wrappedObject, $proxy) use ($parameters) {' . PHP_EOL; $getInstanceBody .= ' $proxy->setProxyInitializer(null);' . PHP_EOL; - $getInstanceBody .= ' $wrappedObject = ' . $factoryName . '::createInstance($parameters);' . PHP_EOL; + $getInstanceBody .= ' $wrappedObject = self::createInstance($parameters);' . PHP_EOL; $getInstanceBody .= ' return true;' . PHP_EOL; $getInstanceBody .= ' }' . PHP_EOL; $getInstanceBody .= ');' . PHP_EOL; @@ -325,16 +334,26 @@ public function getGeneratedFile() { } } - // Generate File - $file->setNamespace('rg\injektor\generated'); + // Dependency require statements $this->usedFactories = array_unique($this->usedFactories); foreach ($this->usedFactories as &$usedFactory) { $usedFactory = str_replace('rg\injektor\generated\\', '', $usedFactory); $usedFactory = $usedFactory . '.php'; } - $file->setRequiredFiles($this->usedFactories); + if ($isLazy) { + // When the class is lazy, only load the dependencies when the real instance is created + $loadDependenciesBody = ''; + foreach ($this->usedFactories as $usedFactory) { + $loadDependenciesBody .= 'require_once \'' . $usedFactory . '\';'; + } + $loadDependenciesMethod->setBody($loadDependenciesBody); + $factoryClass->addMethodFromGenerator($loadDependenciesMethod); + } else { + // When the class is not lazy loaded, we can get all the dependencies right away, because we'll need them for instance creation + $file->setRequiredFiles($this->usedFactories); + } + $file->setClass($factoryClass); - $file->setFilename($this->factoryPath . DIRECTORY_SEPARATOR . $factoryName . '.php'); // Add lazy proxy class if ($isLazy) { diff --git a/src/rg/injektor/generators/LoadDependenciesMethod.php b/src/rg/injektor/generators/LoadDependenciesMethod.php new file mode 100644 index 0000000..81c83b8 --- /dev/null +++ b/src/rg/injektor/generators/LoadDependenciesMethod.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace rg\injektor\generators; + +class LoadDependenciesMethod extends \Zend\Code\Generator\MethodGenerator { + + public function __construct() { + parent::__construct('loadDependencies', [], self::FLAG_PRIVATE | self::FLAG_STATIC); + } +} From b694c693db92c8664f05aad4ad009ddcba072c46 Mon Sep 17 00:00:00 2001 From: Christian Scheb Date: Fri, 16 Mar 2018 15:02:04 +0100 Subject: [PATCH 11/12] Fix newline --- src/rg/injektor/generators/FileGenerator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rg/injektor/generators/FileGenerator.php b/src/rg/injektor/generators/FileGenerator.php index 756fad5..664ae05 100644 --- a/src/rg/injektor/generators/FileGenerator.php +++ b/src/rg/injektor/generators/FileGenerator.php @@ -344,7 +344,7 @@ public function getGeneratedFile() { // When the class is lazy, only load the dependencies when the real instance is created $loadDependenciesBody = ''; foreach ($this->usedFactories as $usedFactory) { - $loadDependenciesBody .= 'require_once \'' . $usedFactory . '\';'; + $loadDependenciesBody .= 'require_once \'' . $usedFactory . '\';' . PHP_EOL; } $loadDependenciesMethod->setBody($loadDependenciesBody); $factoryClass->addMethodFromGenerator($loadDependenciesMethod); From 6e660fef7ce698230b59abdeb38241e519f56755 Mon Sep 17 00:00:00 2001 From: Christian Scheb Date: Fri, 16 Mar 2018 15:34:07 +0100 Subject: [PATCH 12/12] Fix dependency loading --- src/rg/injektor/generators/FileGenerator.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/rg/injektor/generators/FileGenerator.php b/src/rg/injektor/generators/FileGenerator.php index 664ae05..69a6ec5 100644 --- a/src/rg/injektor/generators/FileGenerator.php +++ b/src/rg/injektor/generators/FileGenerator.php @@ -336,21 +336,22 @@ public function getGeneratedFile() { // Dependency require statements $this->usedFactories = array_unique($this->usedFactories); - foreach ($this->usedFactories as &$usedFactory) { + $requiredFactoryFiles = array(); + foreach ($this->usedFactories as $usedFactory) { $usedFactory = str_replace('rg\injektor\generated\\', '', $usedFactory); - $usedFactory = $usedFactory . '.php'; + $requiredFactoryFiles[] = $usedFactory . '.php'; } if ($isLazy) { // When the class is lazy, only load the dependencies when the real instance is created $loadDependenciesBody = ''; - foreach ($this->usedFactories as $usedFactory) { + foreach ($requiredFactoryFiles as $usedFactory) { $loadDependenciesBody .= 'require_once \'' . $usedFactory . '\';' . PHP_EOL; } $loadDependenciesMethod->setBody($loadDependenciesBody); $factoryClass->addMethodFromGenerator($loadDependenciesMethod); } else { // When the class is not lazy loaded, we can get all the dependencies right away, because we'll need them for instance creation - $file->setRequiredFiles($this->usedFactories); + $file->setRequiredFiles($requiredFactoryFiles); } $file->setClass($factoryClass);