Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#97: handle private properties of superclasses #218

Merged
merged 22 commits into from
Jan 2, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
b441aa0
Testing code against the `ClassWithMixedProperties` asset for better …
Ocramius Jan 2, 2015
1f6084f
`ClassWithMixedProperties` should also contain static properties for …
Ocramius Jan 2, 2015
d21ebf2
StaticProxyConstructor for null objects should skip non-static proper…
Ocramius Jan 2, 2015
d7c9d71
Removing unused private method (util class already exists for that pu…
Ocramius Jan 2, 2015
ceacaff
Removing unused variable
Ocramius Jan 2, 2015
f4f0ca2
Skipping static properties when binding properties in a scope localizer
Ocramius Jan 2, 2015
70161a8
Refactoring code to use the `Properties` utility class rather than di…
Ocramius Jan 2, 2015
a81dc9a
Simplified code via existing utility API
Ocramius Jan 2, 2015
327aedd
Private properties should be handled after accessible properties, as …
Ocramius Jan 2, 2015
45e652e
Simplified structure of the method generator by using the parent clas…
Ocramius Jan 2, 2015
ed6cd09
Using `Properties` utility class instead of direct `ReflectionClass` …
Ocramius Jan 2, 2015
7d3b226
Refactoring logic to avoid useless mutation
Ocramius Jan 2, 2015
23a1c12
Using `Properties` utility class instead of direct `ReflectionClass` …
Ocramius Jan 2, 2015
729774a
Using `Properties` utility class instead of direct `ReflectionClass` …
Ocramius Jan 2, 2015
3006353
`PublicPropertiesMap` should ignore static properties
Ocramius Jan 2, 2015
ff5afb8
`PublicPropertiesMap` ignores static properties
Ocramius Jan 2, 2015
3a91ae6
`Properties#getInstanceProperties()` should provide a list of all non…
Ocramius Jan 2, 2015
b22d165
`Properties#getInstanceProperties()` provides a list of all non-stati…
Ocramius Jan 2, 2015
e942958
Test code should only verify instance properties
Ocramius Jan 2, 2015
08b66f9
Value holder constructor should ignore static properties
Ocramius Jan 2, 2015
0c55819
Skipping static properties in constructor codegen
Ocramius Jan 2, 2015
e4eeab8
Using `Properties` utility instead of direct reflection also for test…
Ocramius Jan 2, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
namespace ProxyManager\ProxyGenerator\AccessInterceptor\MethodGenerator;

use ProxyManager\Generator\MagicMethodGenerator;
use ProxyManager\ProxyGenerator\Util\Properties;
use ReflectionClass;
use ReflectionProperty;

Expand All @@ -39,13 +40,12 @@ public function __construct(ReflectionClass $originalClass)
{
parent::__construct($originalClass, '__wakeup');

/* @var $publicProperties \ReflectionProperty[] */
$publicProperties = $originalClass->getProperties(ReflectionProperty::IS_PUBLIC);
$unsetProperties = [];

foreach ($publicProperties as $publicProperty) {
$unsetProperties[] = '$this->' . $publicProperty->getName();
}
$unsetProperties = array_map(
function (ReflectionProperty $property) {
return '$this->' . $property->getName();
},
Properties::fromReflectionClass($originalClass)->getPublicProperties()
);

$this->setBody($unsetProperties ? 'unset(' . implode(', ', $unsetProperties) . ");" : '');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

use ProxyManager\Generator\MethodGenerator;
use ProxyManager\Generator\ParameterGenerator;
use ProxyManager\ProxyGenerator\Util\Properties;
use ReflectionClass;
use Zend\Code\Generator\PropertyGenerator;

Expand All @@ -43,43 +44,40 @@ public function __construct(
PropertyGenerator $prefixInterceptors,
PropertyGenerator $suffixInterceptors
) {
parent::__construct('bindProxyProperties', [], static::FLAG_PRIVATE);
parent::__construct(
'bindProxyProperties',
[
new ParameterGenerator('localizedObject', $originalClass->getName()),
new ParameterGenerator('prefixInterceptors', 'array', []),
new ParameterGenerator('suffixInterceptors', 'array', []),
],
static::FLAG_PRIVATE,
null,
"@override constructor to setup interceptors\n\n"
. "@param \\" . $originalClass->getName() . " \$localizedObject\n"
. "@param \\Closure[] \$prefixInterceptors method interceptors to be used before method logic\n"
. "@param \\Closure[] \$suffixInterceptors method interceptors to be used before method logic"
);

$localizedObject = new ParameterGenerator('localizedObject');
$prefix = new ParameterGenerator('prefixInterceptors');
$suffix = new ParameterGenerator('suffixInterceptors');
$localizedProperties = [];

$localizedObject->setType($originalClass->getName());
$prefix->setDefaultValue([]);
$suffix->setDefaultValue([]);
$prefix->setType('array');
$suffix->setType('array');
$properties = Properties::fromReflectionClass($originalClass);

$this->setParameter($localizedObject);
$this->setParameter($prefix);
$this->setParameter($suffix);
foreach ($properties->getAccessibleProperties() as $property) {
$propertyName = $property->getName();

$localizedProperties = [];
$localizedProperties[] = '$this->' . $propertyName . ' = & $localizedObject->' . $propertyName . ";";
}

foreach ($originalClass->getProperties() as $originalProperty) {
$propertyName = $originalProperty->getName();
foreach ($properties->getPrivateProperties() as $property) {
$propertyName = $property->getName();

if ($originalProperty->isPrivate()) {
$localizedProperties[] = "\\Closure::bind(function () use (\$localizedObject) {\n "
. '$this->' . $propertyName . ' = & $localizedObject->' . $propertyName . ";\n"
. '}, $this, ' . var_export($originalProperty->getDeclaringClass()->getName(), true)
. ')->__invoke();';
} else {
$localizedProperties[] = '$this->' . $propertyName . ' = & $localizedObject->' . $propertyName . ";";
}
$localizedProperties[] = "\\Closure::bind(function () use (\$localizedObject) {\n "
. '$this->' . $propertyName . ' = & $localizedObject->' . $propertyName . ";\n"
. '}, $this, ' . var_export($property->getDeclaringClass()->getName(), true)
. ')->__invoke();';
}

$this->setDocblock(
"@override constructor to setup interceptors\n\n"
. "@param \\" . $originalClass->getName() . " \$localizedObject\n"
. "@param \\Closure[] \$prefixInterceptors method interceptors to be used before method logic\n"
. "@param \\Closure[] \$suffixInterceptors method interceptors to be used before method logic"
);
$this->setBody(
(empty($localizedProperties) ? '' : implode("\n\n", $localizedProperties) . "\n\n")
. '$this->' . $prefixInterceptors->getName() . " = \$prefixInterceptors;\n"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

use ProxyManager\Generator\MethodGenerator;
use ProxyManager\Generator\ParameterGenerator;
use ProxyManager\ProxyGenerator\Util\Properties;
use ReflectionClass;
use ReflectionProperty;
use Zend\Code\Generator\PropertyGenerator;
Expand Down Expand Up @@ -60,8 +61,7 @@ public function __construct(
$this->setParameter($prefix);
$this->setParameter($suffix);

/* @var $publicProperties \ReflectionProperty[] */
$publicProperties = $originalClass->getProperties(ReflectionProperty::IS_PUBLIC);
$publicProperties = Properties::fromReflectionClass($originalClass)->getPublicProperties();
$unsetProperties = [];

foreach ($publicProperties as $publicProperty) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
namespace ProxyManager\ProxyGenerator\NullObject\MethodGenerator;

use ProxyManager\Generator\MethodGenerator;
use ProxyManager\ProxyGenerator\Util\Properties;
use ReflectionClass;
use ReflectionProperty;

Expand All @@ -39,13 +40,12 @@ public function __construct(ReflectionClass $originalClass)
{
parent::__construct('staticProxyConstructor', [], static::FLAG_PUBLIC | static::FLAG_STATIC);

/* @var $publicProperties \ReflectionProperty[] */
$publicProperties = $originalClass->getProperties(ReflectionProperty::IS_PUBLIC);
$nullableProperties = [];

foreach ($publicProperties as $publicProperty) {
$nullableProperties[] = '$instance->' . $publicProperty->getName() . ' = null;';
}
$nullableProperties = array_map(
function (ReflectionProperty $publicProperty) {
return '$instance->' . $publicProperty->getName() . ' = null;';
},
Properties::fromReflectionClass($originalClass)->getPublicProperties()
);

$this->setDocblock("Constructor for null object initialization");
$this->setBody(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
namespace ProxyManager\ProxyGenerator\PropertyGenerator;

use ProxyManager\Generator\Util\UniqueIdentifierGenerator;
use ProxyManager\ProxyGenerator\Util\Properties;
use ReflectionClass;
use ReflectionProperty;
use Zend\Code\Generator\PropertyGenerator;
Expand All @@ -43,7 +44,7 @@ public function __construct(ReflectionClass $originalClass)
{
parent::__construct(UniqueIdentifierGenerator::getIdentifier('publicProperties'));

foreach ($originalClass->getProperties(ReflectionProperty::IS_PUBLIC) as $publicProperty) {
foreach (Properties::fromReflectionClass($originalClass)->getPublicProperties() as $publicProperty) {
$this->publicProperties[$publicProperty->getName()] = true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use ProxyManager\Factory\RemoteObject\AdapterInterface;
use ProxyManager\Generator\MethodGenerator;
use ProxyManager\Generator\ParameterGenerator;
use ProxyManager\ProxyGenerator\Util\Properties;
use ReflectionClass;
use Zend\Code\Generator\PropertyGenerator;

Expand All @@ -41,17 +42,13 @@ class StaticProxyConstructor extends MethodGenerator
*/
public function __construct(ReflectionClass $originalClass, PropertyGenerator $adapter)
{
parent::__construct(
'staticProxyConstructor',
[],
MethodGenerator::FLAG_PUBLIC | MethodGenerator::FLAG_STATIC
);

$adapterName = $adapter->getName();

$this->setParameter(new ParameterGenerator($adapterName, AdapterInterface::class));

$this->setDocblock(
parent::__construct(
'staticProxyConstructor',
[new ParameterGenerator($adapterName, AdapterInterface::class)],
MethodGenerator::FLAG_PUBLIC | MethodGenerator::FLAG_STATIC,
null,
'Constructor for remote object control\n\n'
. '@param \\ProxyManager\\Factory\\RemoteObject\\AdapterInterface \$adapter'
);
Expand All @@ -61,10 +58,8 @@ public function __construct(ReflectionClass $originalClass, PropertyGenerator $a
. '$instance = (new \ReflectionClass(get_class()))->newInstanceWithoutConstructor();' . "\n\n"
. '$instance->' . $adapterName . ' = $' . $adapterName . ';';

foreach ($originalClass->getProperties() as $property) {
if ($property->isPublic() && ! $property->isStatic()) {
$body .= "\nunset(\$instance->" . $property->getName() . ');';
}
foreach (Properties::fromReflectionClass($originalClass)->getPublicProperties() as $property) {
$body .= "\nunset(\$instance->" . $property->getName() . ');';
}

$this->setBody($body . "\n\nreturn \$instance;");
Expand Down
8 changes: 8 additions & 0 deletions src/ProxyManager/ProxyGenerator/Util/Properties.php
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,12 @@ public function getGroupedPrivateProperties()

return $propertiesMap;
}

/**
* @return ReflectionProperty[] indexed by the property internal visibility-aware name (\0*\0propertyName)
*/
public function getInstanceProperties()
{
return array_merge($this->getAccessibleProperties(), $this->getPrivateProperties());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

use ProxyManager\Generator\MethodGenerator;
use ProxyManager\Generator\ParameterGenerator;
use ProxyManager\ProxyGenerator\Util\Properties;
use ReflectionClass;
use ReflectionProperty;
use Zend\Code\Generator\PropertyGenerator;
Expand Down Expand Up @@ -88,7 +89,7 @@ private static function getUnsetPropertiesString(ReflectionClass $class)
function (ReflectionProperty $unsetProperty) {
return 'unset($this->' . $unsetProperty->getName() . ');';
},
$class->getProperties(ReflectionProperty::IS_PUBLIC)
Properties::fromReflectionClass($class)->getPublicProperties()
)
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
use ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy;
use ProxyManager\Proxy\AccessInterceptorInterface;
use ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizerGenerator;
use ProxyManager\ProxyGenerator\Util\Properties;
use ProxyManagerTestAsset\BaseClass;
use ProxyManagerTestAsset\ClassWithCounterConstructor;
use ProxyManagerTestAsset\ClassWithPublicArrayProperty;
Expand Down Expand Up @@ -387,7 +388,7 @@ private function assertProxySynchronized($instance, AccessInterceptorInterface $
{
$reflectionClass = new ReflectionClass($instance);

foreach ($reflectionClass->getProperties() as $property) {
foreach (Properties::fromReflectionClass($reflectionClass)->getInstanceProperties() as $property) {
$property->setAccessible(true);

$this->assertSame(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
use ProxyManager\GeneratorStrategy\FileWriterGeneratorStrategy;
use ProxyManager\Proxy\GhostObjectInterface;
use ProxyManager\ProxyGenerator\LazyLoadingGhostGenerator;
use ProxyManager\ProxyGenerator\Util\Properties;
use ProxyManagerTestAsset\BaseClass;
use ProxyManagerTestAsset\ClassWithCollidingPrivateInheritedProperties;
use ProxyManagerTestAsset\ClassWithCounterConstructor;
Expand Down Expand Up @@ -573,7 +574,9 @@ function ($proxy, $method, $params, & $initializer, array $properties) {
}
);

foreach ((new ReflectionClass(ClassWithMixedProperties::class))->getProperties() as $property) {
$reflectionClass = new ReflectionClass(ClassWithMixedProperties::class);

foreach (Properties::fromReflectionClass($reflectionClass)->getInstanceProperties() as $property) {
$property->setAccessible(true);

$this->assertSame(str_replace('Property', '', $property->getName()), $property->getValue($proxy));
Expand Down Expand Up @@ -662,7 +665,7 @@ private function createInitializer($className, $realInstance, Mock $initializerM
$initializer = null;
$reflectionClass = new ReflectionClass($realInstance);

foreach ($reflectionClass->getProperties() as $property) {
foreach (Properties::fromReflectionClass($reflectionClass)->getInstanceProperties() as $property) {
$property->setAccessible(true);
$property->setValue($proxy, $property->getValue($realInstance));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
use ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy;
use ProxyManager\Proxy\GhostObjectInterface;
use ProxyManager\ProxyGenerator\LazyLoadingGhostGenerator;
use ProxyManager\ProxyGenerator\Util\Properties;
use ProxyManagerTestAsset\BaseClass;
use ReflectionClass;
use stdClass;
Expand Down Expand Up @@ -128,7 +129,7 @@ public function getTestedClasses()
$reflectionProperties = [];
$reflectionClass = new ReflectionClass($testedClass[0]);

foreach ($reflectionClass->getProperties() as $property) {
foreach (Properties::fromReflectionClass($reflectionClass)->getInstanceProperties() as $property) {
$property->setAccessible(true);

$reflectionProperties[$property->getName()] = $property;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,7 @@ public function testCanGenerateMultipleDifferentProxiesForSameClass($className)
$initializer = function () {
};

$reflectionClass = new ReflectionClass($className);
$generated = [
$generated = [
$ghostProxyFactory->createProxy($className, $initializer),
$virtualProxyFactory->createProxy($className, $initializer),
$accessInterceptorFactory->createProxy(new $className()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@

use PHPUnit_Framework_TestCase;
use ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizer\MethodGenerator\BindProxyProperties;
use ProxyManagerTestAsset\ClassWithMixedProperties;
use ProxyManagerTestAsset\ClassWithPrivateProperties;
use ProxyManagerTestAsset\ClassWithProtectedProperties;
use ProxyManagerTestAsset\ClassWithPublicProperties;
use ReflectionClass;
use Zend\Code\Generator\PropertyGenerator;

Expand Down Expand Up @@ -85,36 +85,42 @@ public function testSignature()
public function testBodyStructure()
{
$method = new BindProxyProperties(
new ReflectionClass(ClassWithPublicProperties::class),
new ReflectionClass(ClassWithMixedProperties::class),
$this->prefixInterceptors,
$this->suffixInterceptors
);

$this->assertSame(
'$this->property0 = & $localizedObject->property0;
$expectedCode = <<<'PHP'
$this->publicProperty0 = & $localizedObject->publicProperty0;

$this->property1 = & $localizedObject->property1;

$this->property2 = & $localizedObject->property2;
$this->publicProperty1 = & $localizedObject->publicProperty1;

$this->property3 = & $localizedObject->property3;
$this->publicProperty2 = & $localizedObject->publicProperty2;

$this->property4 = & $localizedObject->property4;
$this->protectedProperty0 = & $localizedObject->protectedProperty0;

$this->property5 = & $localizedObject->property5;
$this->protectedProperty1 = & $localizedObject->protectedProperty1;

$this->property6 = & $localizedObject->property6;
$this->protectedProperty2 = & $localizedObject->protectedProperty2;

$this->property7 = & $localizedObject->property7;
\Closure::bind(function () use ($localizedObject) {
$this->privateProperty0 = & $localizedObject->privateProperty0;
}, $this, 'ProxyManagerTestAsset\\ClassWithMixedProperties')->__invoke();

$this->property8 = & $localizedObject->property8;
\Closure::bind(function () use ($localizedObject) {
$this->privateProperty1 = & $localizedObject->privateProperty1;
}, $this, 'ProxyManagerTestAsset\\ClassWithMixedProperties')->__invoke();

$this->property9 = & $localizedObject->property9;
\Closure::bind(function () use ($localizedObject) {
$this->privateProperty2 = & $localizedObject->privateProperty2;
}, $this, 'ProxyManagerTestAsset\\ClassWithMixedProperties')->__invoke();

$this->pre = $prefixInterceptors;
$this->post = $suffixInterceptors;',
$method->getBody()
);
$this->post = $suffixInterceptors;
PHP;


$this->assertSame($expectedCode, $method->getBody());
}

public function testBodyStructureWithProtectedProperties()
Expand Down
Loading