Skip to content

Commit 2ee42e8

Browse files
committed
[PropertyInfo] Extract public properties first in ReflectionExtractor
1 parent dd061aa commit 2ee42e8

File tree

4 files changed

+93
-20
lines changed

4 files changed

+93
-20
lines changed

src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,29 @@ public function getTypesFromConstructor(string $class, string $property): ?array
207207

208208
public function getType(string $class, string $property, array $context = []): ?Type
209209
{
210+
// BC layer, remove context key in 8.0
211+
$extractPublicPropertiesFirst = array_key_exists('extract_public_properties_first', $context);
212+
if (!$extractPublicPropertiesFirst) {
213+
trigger_deprecation('symfony/property-info', '7.3', 'Not setting "extract_public_properties_first" context key is deprecated, it will default to "true" in 8.0.');
214+
}
215+
216+
if ($extractPublicPropertiesFirst) {
217+
try {
218+
$reflectionClass = new \ReflectionClass($class);
219+
$reflectionProperty = $reflectionClass->getProperty($property);
220+
} catch (\ReflectionException) {
221+
return null;
222+
}
223+
224+
if ($reflectionProperty->isPublic()) {
225+
try {
226+
return $this->typeResolver->resolve($reflectionProperty);
227+
} catch (UnsupportedException $e) {
228+
throw $e;
229+
}
230+
}
231+
}
232+
210233
[$mutatorReflection, $prefix] = $this->getMutatorMethod($class, $property);
211234

212235
if ($mutatorReflection) {
@@ -240,27 +263,30 @@ public function getType(string $class, string $property, array $context = []): ?
240263
}
241264
}
242265

243-
try {
244-
$reflectionClass = new \ReflectionClass($class);
245-
$reflectionProperty = $reflectionClass->getProperty($property);
246-
} catch (\ReflectionException) {
247-
return null;
248-
}
266+
// BC layer, remove block in 8.0
267+
if (!$extractPublicPropertiesFirst) {
268+
try {
269+
$reflectionClass = new \ReflectionClass($class);
270+
$reflectionProperty = $reflectionClass->getProperty($property);
271+
} catch (\ReflectionException) {
272+
return null;
273+
}
249274

250-
try {
251-
return $this->typeResolver->resolve($reflectionProperty);
252-
} catch (UnsupportedException) {
253-
}
275+
try {
276+
return $this->typeResolver->resolve($reflectionProperty);
277+
} catch (UnsupportedException) {
278+
}
254279

255-
if (null === $defaultValue = ($reflectionClass->getDefaultProperties()[$property] ?? null)) {
256-
return null;
257-
}
280+
if (null === $defaultValue = ($reflectionClass->getDefaultProperties()[$property] ?? null)) {
281+
return null;
282+
}
258283

259-
$typeIdentifier = TypeIdentifier::from(static::MAP_TYPES[\gettype($defaultValue)] ?? \gettype($defaultValue));
260-
$type = 'array' === $typeIdentifier->value ? Type::array() : Type::builtin($typeIdentifier);
284+
$typeIdentifier = TypeIdentifier::from(static::MAP_TYPES[\gettype($defaultValue)] ?? \gettype($defaultValue));
285+
$type = 'array' === $typeIdentifier->value ? Type::array() : Type::builtin($typeIdentifier);
261286

262-
if ($this->isNullableProperty($class, $property)) {
263-
$type = Type::nullable($type);
287+
if ($this->isNullableProperty($class, $property)) {
288+
$type = Type::nullable($type);
289+
}
264290
}
265291

266292
return $type;
@@ -738,7 +764,7 @@ private function isAllowedProperty(string $class, string $property, bool $writeA
738764
/**
739765
* Gets the accessor method.
740766
*
741-
* Returns an array with a the instance of \ReflectionMethod as first key
767+
* Returns an array with the instance of \ReflectionMethod as first key
742768
* and the prefix of the method as second or null if not found.
743769
*/
744770
private function getAccessorMethod(string $class, string $property): ?array
@@ -764,7 +790,7 @@ private function getAccessorMethod(string $class, string $property): ?array
764790
}
765791

766792
/**
767-
* Returns an array with a the instance of \ReflectionMethod as first key
793+
* Returns an array with the instance of \ReflectionMethod as first key
768794
* and the prefix of the method as second or null if not found.
769795
*/
770796
private function getMutatorMethod(string $class, string $property): ?array

src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,4 +1024,24 @@ public static function extractConstructorTypesProvider(): iterable
10241024
yield ['dateTime', Type::object(\DateTimeImmutable::class)];
10251025
yield ['ddd', null];
10261026
}
1027+
1028+
/**
1029+
* @dataProvider extractPropertyOrderProvider
1030+
*/
1031+
public function testPublicPropertyExtractedFirst(string $property, Type $type)
1032+
{
1033+
$this->assertEquals(
1034+
$type,
1035+
$this->extractor->getType('Symfony\Component\PropertyInfo\Tests\Fixtures\PublicPropertyWithHasDummy', $property, ['extract_public_properties_first' => true])
1036+
);
1037+
}
1038+
1039+
/**
1040+
* @return iterable<array{0: string, 1: Type}>
1041+
*/
1042+
public static function extractPropertyOrderProvider(): iterable
1043+
{
1044+
yield ['publicProperty', Type::string()];
1045+
yield ['privateProperty', Type::bool()];
1046+
}
10271047
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\PropertyInfo\Tests\Fixtures;
13+
14+
class PublicPropertyWithHasDummy
15+
{
16+
public string $publicProperty;
17+
18+
private string $privateProperty;
19+
20+
public function hasPublicProperty(): bool
21+
{
22+
}
23+
24+
public function hasPrivateProperty(): bool
25+
{
26+
}
27+
}

src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -987,7 +987,7 @@ private function getType(string $currentClass, string $attribute): Type|array|nu
987987
private function getPropertyType(string $className, string $property): Type|array|null
988988
{
989989
if (class_exists(Type::class) && method_exists($this->propertyTypeExtractor, 'getType')) {
990-
return $this->propertyTypeExtractor->getType($className, $property);
990+
return $this->propertyTypeExtractor->getType($className, $property, context: [ 'extract_public_properties_first' => true ]);
991991
}
992992

993993
return $this->propertyTypeExtractor->getTypes($className, $property);

0 commit comments

Comments
 (0)