Skip to content

Commit c5b3f45

Browse files
committed
[PropertyInfo] Added support for extracting type from constructor
1 parent b0facfe commit c5b3f45

File tree

4 files changed

+138
-1
lines changed

4 files changed

+138
-1
lines changed

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

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,19 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp
4444
private $mutatorPrefixes;
4545
private $accessorPrefixes;
4646
private $arrayMutatorPrefixes;
47+
private $enableConstructorExtraction;
4748

4849
/**
4950
* @param string[]|null $mutatorPrefixes
5051
* @param string[]|null $accessorPrefixes
5152
* @param string[]|null $arrayMutatorPrefixes
5253
*/
53-
public function __construct(array $mutatorPrefixes = null, array $accessorPrefixes = null, array $arrayMutatorPrefixes = null)
54+
public function __construct(array $mutatorPrefixes = null, array $accessorPrefixes = null, array $arrayMutatorPrefixes = null, bool $enableConstructorExtraction = true)
5455
{
5556
$this->mutatorPrefixes = null !== $mutatorPrefixes ? $mutatorPrefixes : self::$defaultMutatorPrefixes;
5657
$this->accessorPrefixes = null !== $accessorPrefixes ? $accessorPrefixes : self::$defaultAccessorPrefixes;
5758
$this->arrayMutatorPrefixes = null !== $arrayMutatorPrefixes ? $arrayMutatorPrefixes : self::$defaultArrayMutatorPrefixes;
59+
$this->enableConstructorExtraction = $enableConstructorExtraction;
5860
}
5961

6062
/**
@@ -107,6 +109,13 @@ public function getTypes($class, $property, array $context = array())
107109
if ($fromAccessor = $this->extractFromAccessor($class, $property)) {
108110
return $fromAccessor;
109111
}
112+
113+
if (
114+
isset($context['enable_constructor_extraction']) ? $context['enable_constructor_extraction'] : $this->enableConstructorExtraction &&
115+
$fromConstructor = $this->extractFromConstructor($class, $property)
116+
) {
117+
return $fromConstructor;
118+
}
110119
}
111120

112121
/**
@@ -185,6 +194,40 @@ private function extractFromAccessor(string $class, string $property): ?array
185194
return null;
186195
}
187196

197+
/**
198+
* Tries to extract type information from constructor.
199+
*
200+
* @return Type[]|null
201+
*/
202+
private function extractFromConstructor(string $class, string $property): ?array
203+
{
204+
try {
205+
$reflectionClass = new \ReflectionClass($class);
206+
} catch (\ReflectionException $e) {
207+
return null;
208+
}
209+
210+
$constructor = $reflectionClass->getConstructor();
211+
212+
if (!$constructor) {
213+
return null;
214+
}
215+
216+
foreach ($constructor->getParameters() as $parameter) {
217+
if ($property !== $parameter->name) {
218+
continue;
219+
}
220+
221+
return array($this->extractFromReflectionType($parameter->getType()));
222+
}
223+
224+
if ($parentClass = $reflectionClass->getParentClass()) {
225+
return $this->extractFromConstructor($parentClass->getName(), $property);
226+
}
227+
228+
return null;
229+
}
230+
188231
private function extractFromReflectionType(\ReflectionType $reflectionType): Type
189232
{
190233
$phpTypeOrClass = $reflectionType->getName();

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,24 @@ public function testGetPropertiesWithNoPrefixes()
114114
);
115115
}
116116

117+
public function testGetPropertiesPhp71()
118+
{
119+
$noPrefixExtractor = new ReflectionExtractor();
120+
121+
$this->assertSame(
122+
array(
123+
'string',
124+
'stringOrNull',
125+
'foo',
126+
'buz',
127+
'bar',
128+
'baz',
129+
'intWithAccessor',
130+
),
131+
$noPrefixExtractor->getProperties('Symfony\Component\PropertyInfo\Tests\Fixtures\Php71Dummy')
132+
);
133+
}
134+
117135
/**
118136
* @dataProvider typesProvider
119137
*/
@@ -171,9 +189,22 @@ public function php71TypesProvider()
171189
array('bar', array(new Type(Type::BUILTIN_TYPE_INT, true))),
172190
array('baz', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING)))),
173191
array('donotexist', null),
192+
array('string', array(new Type(Type::BUILTIN_TYPE_STRING, false))),
193+
array('stringOrNull', array(new Type(Type::BUILTIN_TYPE_STRING, true))),
194+
array('intPrivate', array(new Type(Type::BUILTIN_TYPE_INT, false))),
195+
array('intWithAccessor', array(new Type(Type::BUILTIN_TYPE_INT, false))),
174196
);
175197
}
176198

199+
public function testExtractPhp71TypeWithParentConstructor()
200+
{
201+
$property = 'string';
202+
$type = array(new Type(Type::BUILTIN_TYPE_STRING, false));
203+
$this->assertEquals($type, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Php71DummyChild', $property, array()));
204+
$this->assertEquals($type, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Php71DummyChild2', $property, array()));
205+
$this->assertEquals($type, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Php71DummyChild3', $property, array()));
206+
}
207+
177208
/**
178209
* @dataProvider getReadableProperties
179210
*/

src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php71Dummy.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,22 @@
1616
*/
1717
class Php71Dummy
1818
{
19+
public $string;
20+
21+
public $stringOrNull;
22+
23+
private $intPrivate;
24+
25+
private $intWithAccessor;
26+
27+
public function __construct(string $string, ?string $stringOrNull, int $intPrivate, int $intWithAccessor)
28+
{
29+
$this->string = $string;
30+
$this->stringOrNull = $stringOrNull;
31+
$this->intPrivate = $intPrivate;
32+
$this->intWithAccessor = $intWithAccessor;
33+
}
34+
1935
public function getFoo(): ?array
2036
{
2137
}
@@ -31,4 +47,9 @@ public function setBar(?int $bar)
3147
public function addBaz(string $baz)
3248
{
3349
}
50+
51+
public function getIntWithAccessor()
52+
{
53+
return $this->intWithAccessor;
54+
}
3455
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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 Php71DummyParent
15+
{
16+
public $string;
17+
18+
public function __construct(string $string)
19+
{
20+
$this->string = $string;
21+
}
22+
}
23+
24+
class Php71DummyChild extends Php71DummyParent
25+
{
26+
public function __construct(string $string)
27+
{
28+
parent::__construct($string);
29+
}
30+
}
31+
32+
class Php71DummyChild2 extends Php71DummyParent
33+
{
34+
}
35+
36+
class Php71DummyChild3 extends Php71DummyParent
37+
{
38+
public function __construct()
39+
{
40+
parent::__construct('hello');
41+
}
42+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy