diff --git a/src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGet.php b/src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGet.php index 0da73a94b..769dd7049 100644 --- a/src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGet.php +++ b/src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGet.php @@ -20,6 +20,7 @@ use ProxyManager\Generator\MagicMethodGenerator; use ProxyManager\Generator\ParameterGenerator; +use ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\InitializationTracker; use ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\PrivatePropertiesMap; use ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\ProtectedPropertiesMap; use ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap; @@ -40,13 +41,17 @@ class MagicGet extends MagicMethodGenerator * @var string */ private $callParentTemplate = <<<'PHP' -%s +$this->%s && ! $this->%s && $this->%s('__get', array('name' => $name)); if (isset(self::$%s[$name])) { return $this->$name; } if (isset(self::$%s[$name])) { + if ($this->%s) { + return $this->$name; + } + // check protected property access via compatible class $callers = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2); $caller = isset($callers[1]) ? $callers[1] : []; @@ -81,7 +86,7 @@ class MagicGet extends MagicMethodGenerator return $accessor($this); } - if ('ReflectionProperty' === $class) { + if ($this->%s || 'ReflectionProperty' === $class) { $tmpClass = key(self::$%s[$name]); $cacheKey = $tmpClass . '#' . $name; $accessor = isset($accessorCache[$cacheKey]) @@ -104,6 +109,7 @@ class MagicGet extends MagicMethodGenerator * @param PublicPropertiesMap $publicProperties * @param ProtectedPropertiesMap $protectedProperties * @param PrivatePropertiesMap $privateProperties + * @param InitializationTracker $initializationTracker */ public function __construct( ReflectionClass $originalClass, @@ -111,7 +117,8 @@ public function __construct( MethodGenerator $callInitializer, PublicPropertiesMap $publicProperties, ProtectedPropertiesMap $protectedProperties, - PrivatePropertiesMap $privateProperties + PrivatePropertiesMap $privateProperties, + InitializationTracker $initializationTracker ) { parent::__construct($originalClass, '__get', [new ParameterGenerator('name')]); @@ -130,13 +137,16 @@ public function __construct( $this->setBody(sprintf( $this->callParentTemplate, - '$this->' . $initializerProperty->getName() . ' && $this->' . $callInitializer->getName() - . '(\'__get\', array(\'name\' => $name));', + $initializerProperty->getName(), + $initializationTracker->getName(), + $callInitializer->getName(), $publicProperties->getName(), $protectedProperties->getName(), + $initializationTracker->getName(), $protectedProperties->getName(), $privateProperties->getName(), $privateProperties->getName(), + $initializationTracker->getName(), $privateProperties->getName(), $parentAccess )); diff --git a/src/ProxyManager/ProxyGenerator/LazyLoadingGhostGenerator.php b/src/ProxyManager/ProxyGenerator/LazyLoadingGhostGenerator.php index 466bb0d4e..15800e2bc 100644 --- a/src/ProxyManager/ProxyGenerator/LazyLoadingGhostGenerator.php +++ b/src/ProxyManager/ProxyGenerator/LazyLoadingGhostGenerator.php @@ -96,7 +96,8 @@ function (MethodGenerator $generatedMethod) use ($originalClass, $classGenerator $init, $publicProperties, $protectedProperties, - $privateProperties + $privateProperties, + $initializationTracker ), new MagicSet( $originalClass, diff --git a/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGetTest.php b/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGetTest.php index ed8422b0c..e9b2395de 100644 --- a/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGetTest.php +++ b/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGetTest.php @@ -20,6 +20,7 @@ use PHPUnit_Framework_TestCase; use ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator\MagicGet; +use ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\InitializationTracker; use ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\PrivatePropertiesMap; use ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\ProtectedPropertiesMap; use ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap; @@ -64,17 +65,26 @@ class MagicGetTest extends PHPUnit_Framework_TestCase */ protected $privateProperties; + /** + * @var InitializationTracker|\PHPUnit_Framework_MockObject_MockObject + */ + protected $initializationTracker; + /** * @var string */ private $expectedCode = <<<'PHP' -$this->foo && $this->baz('__get', array('name' => $name)); +$this->foo && ! $this->init && $this->baz('__get', array('name' => $name)); if (isset(self::$bar[$name])) { return $this->$name; } if (isset(self::$baz[$name])) { + if ($this->init) { + return $this->$name; + } + // check protected property access via compatible class $callers = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2); $caller = isset($callers[1]) ? $callers[1] : []; @@ -109,7 +119,7 @@ class MagicGetTest extends PHPUnit_Framework_TestCase return $accessor($this); } - if ('ReflectionProperty' === $class) { + if ($this->init || 'ReflectionProperty' === $class) { $tmpClass = key(self::$tab[$name]); $cacheKey = $tmpClass . '#' . $name; $accessor = isset($accessorCache[$cacheKey]) @@ -144,6 +154,10 @@ protected function setUp() ->getMockBuilder(PrivatePropertiesMap::class) ->disableOriginalConstructor() ->getMock(); + $this->initializationTracker = $this + ->getMockBuilder(InitializationTracker::class) + ->disableOriginalConstructor() + ->getMock(); $this->initializer->expects($this->any())->method('getName')->will($this->returnValue('foo')); $this->initMethod->expects($this->any())->method('getName')->will($this->returnValue('baz')); @@ -151,6 +165,7 @@ protected function setUp() $this->publicProperties->expects($this->any())->method('getName')->will($this->returnValue('bar')); $this->protectedProperties->expects($this->any())->method('getName')->will($this->returnValue('baz')); $this->privateProperties->expects($this->any())->method('getName')->will($this->returnValue('tab')); + $this->initializationTracker->expects($this->any())->method('getName')->will($this->returnValue('init')); } /** @@ -164,7 +179,8 @@ public function testBodyStructure() $this->initMethod, $this->publicProperties, $this->protectedProperties, - $this->privateProperties + $this->privateProperties, + $this->initializationTracker ); $this->assertSame('__get', $magicGet->getName()); @@ -184,7 +200,8 @@ public function testBodyStructureWithOverriddenMagicGet() $this->initMethod, $this->publicProperties, $this->protectedProperties, - $this->privateProperties + $this->privateProperties, + $this->initializationTracker ); $this->assertSame('__get', $magicGet->getName());