diff --git a/.travis.yml b/.travis.yml index 7c855bb..6920f64 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,5 +3,6 @@ php: - '7.1' - '7.2' - '7.3' + - '7.4' install: - composer install diff --git a/composer.json b/composer.json index 0834394..100c28c 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "require-dev": { "symfony/var-dumper": "^3.3", "symfony/debug": "^3.3", - "phpunit/phpunit": "^6.4", - "mark-gerarts/phpstan-automapper-plus": "^0.1.0" + "mark-gerarts/phpstan-automapper-plus": "^0.1.0", + "phpunit/phpunit": "^7.0" } } diff --git a/src/PropertyAccessor/PropertyAccessor.php b/src/PropertyAccessor/PropertyAccessor.php index f4efc2f..746529e 100644 --- a/src/PropertyAccessor/PropertyAccessor.php +++ b/src/PropertyAccessor/PropertyAccessor.php @@ -59,12 +59,12 @@ public function setProperty($object, string $propertyName, $value): void */ public function getPropertyNames($object): array { - $propertyNames = []; - foreach ((array) $object as $propertyPath => $value) { - $propertyNames[] = $this->getRealName($propertyPath); + $names = []; + foreach ($this->getReflectionProperties($object) as $reflectionProperty) { + $names[] = $reflectionProperty->getName(); } - return $propertyNames; + return $names; } /** @@ -94,20 +94,13 @@ protected function getPrivate($object, string $propertyName) */ protected function setPrivate($object, string $propertyName, $value): void { - $reflectionClass = new \ReflectionClass($object); - - // Parent properties are not included in the reflection class, so we'll - // go up the inheritance chain and check if the property exists in one - // of the parents. - while ( - !$reflectionClass->hasProperty($propertyName) - && $parent = $reflectionClass->getParentClass() - ) { - $reflectionClass = $parent; + $property = $this->getReflectionProperty($object, $propertyName); + if ($property === null) { + return; } - $reflectionProperty = $reflectionClass->getProperty($propertyName); - $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($object, $value); + + $property->setAccessible(true); + $property->setValue($object, $value); } /** @@ -125,18 +118,33 @@ private function isPublic($object, string $propertyName): bool } /** - * @param string $propertyPath - * @return string + * @param $object + * @return iterable|\ReflectionProperty[] */ - private function getRealName(string $propertyPath): string - { - $currChar = \strlen($propertyPath) - 1; - $realName = ''; - while ($currChar >= 0 && $propertyPath[$currChar] !== "\x00") { - $realName = $propertyPath[$currChar] . $realName; - $currChar--; + private function getReflectionProperties($object): iterable { + $reflectionClass = new \ReflectionObject($object); + $properties = $reflectionClass->getProperties(); + foreach ($properties as $property) { + yield $property; + } + + + // Parent properties are not included in the reflection class, so we'll + // go up the inheritance chain and collect private properties. + while ($reflectionClass = $reflectionClass->getParentClass()) { + foreach ($reflectionClass->getProperties(\ReflectionProperty::IS_PRIVATE) as $property) { + yield $property; + } + } + } + + private function getReflectionProperty($object, string $propertyName): ?\ReflectionProperty { + foreach ($this->getReflectionProperties($object) as $property) { + if ($property->getName() === $propertyName) { + return $property; + } } - return $realName; + return null; } } diff --git a/test/Models/Typed/TypedDestination.php b/test/Models/Typed/TypedDestination.php new file mode 100644 index 0000000..0c50632 --- /dev/null +++ b/test/Models/Typed/TypedDestination.php @@ -0,0 +1,8 @@ +assertEquals('phone-value', $source->getPhone()); } + + public function testItGetsTypedPropertyNames() + { + // Skip the test for PHP versions that don't support typed properties. + // There might be a better way? + if (PHP_VERSION_ID < 70400) { + $this->assertTrue(true); + return; + } + + $accessor = new PropertyAccessor(); + $destination = new TypedDestination(); + + $properties = $accessor->getPropertyNames($destination); + + $this->assertEquals(['name'], $properties); + } }