From 48b85c6c14a840609aa2b260cdabd99260459e52 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 9 Jan 2015 22:36:21 +0100 Subject: [PATCH 1/3] #224 - GhostObjects can simply ignore scope checks during lazy-loading (temporarily fixes #210) --- .../MethodGenerator/MagicGet.php | 11 +++++++--- .../LazyLoadingGhostGenerator.php | 3 ++- .../MethodGenerator/MagicGetTest.php | 21 +++++++++++++++---- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGet.php b/src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGet.php index 0da73a94b..9b86756e9 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; @@ -53,7 +54,7 @@ class MagicGet extends MagicMethodGenerator $object = isset($caller['object']) ? $caller['object'] : ''; $expectedType = self::$%s[$name]; - if ($object instanceof $expectedType) { + if ($this->%s || $object instanceof $expectedType) { return $this->$name; } @@ -81,7 +82,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 +105,7 @@ class MagicGet extends MagicMethodGenerator * @param PublicPropertiesMap $publicProperties * @param ProtectedPropertiesMap $protectedProperties * @param PrivatePropertiesMap $privateProperties + * @param InitializationTracker $initializationTracker */ public function __construct( ReflectionClass $originalClass, @@ -111,7 +113,8 @@ public function __construct( MethodGenerator $callInitializer, PublicPropertiesMap $publicProperties, ProtectedPropertiesMap $protectedProperties, - PrivatePropertiesMap $privateProperties + PrivatePropertiesMap $privateProperties, + InitializationTracker $initializationTracker ) { parent::__construct($originalClass, '__get', [new ParameterGenerator('name')]); @@ -135,8 +138,10 @@ public function __construct( $publicProperties->getName(), $protectedProperties->getName(), $protectedProperties->getName(), + $initializationTracker->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..3d354b78c 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,6 +65,11 @@ class MagicGetTest extends PHPUnit_Framework_TestCase */ protected $privateProperties; + /** + * @var InitializationTracker|\PHPUnit_Framework_MockObject_MockObject + */ + protected $initializationTracker; + /** * @var string */ @@ -81,7 +87,7 @@ class MagicGetTest extends PHPUnit_Framework_TestCase $object = isset($caller['object']) ? $caller['object'] : ''; $expectedType = self::$baz[$name]; - if ($object instanceof $expectedType) { + if ($this->init || $object instanceof $expectedType) { return $this->$name; } @@ -109,7 +115,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 +150,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 +161,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 +175,8 @@ public function testBodyStructure() $this->initMethod, $this->publicProperties, $this->protectedProperties, - $this->privateProperties + $this->privateProperties, + $this->initializationTracker ); $this->assertSame('__get', $magicGet->getName()); @@ -184,7 +196,8 @@ public function testBodyStructureWithOverriddenMagicGet() $this->initMethod, $this->publicProperties, $this->protectedProperties, - $this->privateProperties + $this->privateProperties, + $this->initializationTracker ); $this->assertSame('__get', $magicGet->getName()); From da7339e4930c34577486e51a4ab0d9f3d468ace3 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 9 Jan 2015 22:42:35 +0100 Subject: [PATCH 2/3] #224 - minor performance optimization --- .../LazyLoadingGhost/MethodGenerator/MagicGet.php | 8 ++++++-- .../LazyLoadingGhost/MethodGenerator/MagicGetTest.php | 6 +++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGet.php b/src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGet.php index 9b86756e9..e8faa8096 100644 --- a/src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGet.php +++ b/src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGet.php @@ -48,13 +48,17 @@ class MagicGet extends MagicMethodGenerator } 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] : []; $object = isset($caller['object']) ? $caller['object'] : ''; $expectedType = self::$%s[$name]; - if ($this->%s || $object instanceof $expectedType) { + if ($object instanceof $expectedType) { return $this->$name; } @@ -137,8 +141,8 @@ public function __construct( . '(\'__get\', array(\'name\' => $name));', $publicProperties->getName(), $protectedProperties->getName(), - $protectedProperties->getName(), $initializationTracker->getName(), + $protectedProperties->getName(), $privateProperties->getName(), $privateProperties->getName(), $initializationTracker->getName(), diff --git a/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGetTest.php b/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGetTest.php index 3d354b78c..96582cf0a 100644 --- a/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGetTest.php +++ b/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGetTest.php @@ -81,13 +81,17 @@ class MagicGetTest extends PHPUnit_Framework_TestCase } 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] : []; $object = isset($caller['object']) ? $caller['object'] : ''; $expectedType = self::$baz[$name]; - if ($this->init || $object instanceof $expectedType) { + if ($object instanceof $expectedType) { return $this->$name; } From 1fad9fe1bf30f6f902484dc9b997b08886c81f1e Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 9 Jan 2015 22:46:39 +0100 Subject: [PATCH 3/3] #224 - further performance optimizations (avoiding recursive calls when not needed) --- .../LazyLoadingGhost/MethodGenerator/MagicGet.php | 7 ++++--- .../LazyLoadingGhost/MethodGenerator/MagicGetTest.php | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGet.php b/src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGet.php index e8faa8096..769dd7049 100644 --- a/src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGet.php +++ b/src/ProxyManager/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGet.php @@ -41,7 +41,7 @@ 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; @@ -137,8 +137,9 @@ 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(), diff --git a/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGetTest.php b/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGetTest.php index 96582cf0a..e9b2395de 100644 --- a/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGetTest.php +++ b/tests/ProxyManagerTest/ProxyGenerator/LazyLoadingGhost/MethodGenerator/MagicGetTest.php @@ -74,7 +74,7 @@ class MagicGetTest extends PHPUnit_Framework_TestCase * @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;