Skip to content

Commit a070114

Browse files
xificurkondrejmirtes
authored andcommitted
NetteObjectClassReflectionExtension: add test, fixed PHP 7.2 compatibility.
1 parent 53edd54 commit a070114

File tree

5 files changed

+198
-2
lines changed

5 files changed

+198
-2
lines changed

phpstan.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ parameters:
44

55
ignoreErrors:
66
- '#PHPUnit_Framework_MockObject_MockObject given#'
7+
- '# but returns PHPUnit_Framework_MockObject_MockObject.#'
78
- '#Access to an undefined property PHPUnit_Framework_MockObject_MockObject::\$[a-zA-Z0-9_]+#'

src/Reflection/Nette/NetteObjectClassReflectionExtension.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class NetteObjectClassReflectionExtension implements MethodsClassReflectionExten
1313

1414
public function hasProperty(ClassReflection $classReflection, string $propertyName): bool
1515
{
16-
if (!$classReflection->isSubclassOf('Nette\Object')) {
16+
if (!$this->inheritsFromNetteObject($classReflection->getNativeReflection())) {
1717
return false;
1818
}
1919

@@ -57,7 +57,7 @@ public function getProperty(ClassReflection $classReflection, string $propertyNa
5757
public function hasMethod(ClassReflection $classReflection, string $methodName): bool
5858
{
5959
$traitNames = $this->getTraitNames($classReflection->getNativeReflection());
60-
if (!$classReflection->isSubclassOf('Nette\Object') && !in_array(\Nette\SmartObject::class, $traitNames, true)) {
60+
if (!in_array(\Nette\SmartObject::class, $traitNames, true) && !$this->inheritsFromNetteObject($classReflection->getNativeReflection())) {
6161
return false;
6262
}
6363

@@ -88,4 +88,15 @@ private function getTraitNames(\ReflectionClass $class): array
8888
return $traitNames;
8989
}
9090

91+
private function inheritsFromNetteObject(\ReflectionClass $class): bool
92+
{
93+
while (($parentClass = $class->getParentClass()) !== false) {
94+
if ($parentClass->getName() === 'Nette\Object') {
95+
return true;
96+
}
97+
}
98+
99+
return false;
100+
}
101+
91102
}
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Reflection\Nette;
4+
5+
use PHPStan\Reflection\ClassReflection;
6+
use PHPStan\Reflection\MethodReflection;
7+
use PHPStan\Reflection\PropertyReflection;
8+
9+
class NetteObjectClassReflectionExtensionTest extends \PHPUnit\Framework\TestCase
10+
{
11+
12+
/** @var \PHPStan\Reflection\Nette\NetteObjectClassReflectionExtension */
13+
private $extension;
14+
15+
protected function setUp()
16+
{
17+
$this->extension = new NetteObjectClassReflectionExtension();
18+
}
19+
20+
/**
21+
* @return mixed[]
22+
*/
23+
public function dataHasMethod(): array
24+
{
25+
$data = [];
26+
$data[] = [
27+
\PHPStan\Tests\SmartObjectChild::class,
28+
'onPublicEvent',
29+
true,
30+
];
31+
$data[] = [
32+
\PHPStan\Tests\SmartObjectChild::class,
33+
'onProtectedEvent',
34+
false,
35+
];
36+
if (PHP_VERSION_ID < 70200) { // PHP 7.2 is incompatible with Nette\Object.
37+
$data[] = [
38+
'PHPStan\Tests\NetteObjectChild',
39+
'onPublicEvent',
40+
true,
41+
];
42+
$data[] = [
43+
'PHPStan\Tests\NetteObjectChild',
44+
'onProtectedEvent',
45+
false,
46+
];
47+
}
48+
return $data;
49+
}
50+
51+
/**
52+
* @dataProvider dataHasMethod
53+
* @param string $className
54+
* @param string $method
55+
* @param bool $result
56+
*/
57+
public function testHasMethod(string $className, string $method, bool $result)
58+
{
59+
$classReflection = $this->mockClassReflection(new \ReflectionClass($className));
60+
$this->assertSame($result, $this->extension->hasMethod($classReflection, $method));
61+
}
62+
63+
/**
64+
* @return mixed[]
65+
*/
66+
public function dataHasProperty(): array
67+
{
68+
$data = [];
69+
$data[] = [
70+
\PHPStan\Tests\SmartObjectChild::class,
71+
'foo',
72+
false,
73+
];
74+
if (PHP_VERSION_ID < 70200) { // PHP 7.2 is incompatible with Nette\Object.
75+
$data[] = [
76+
'PHPStan\Tests\NetteObjectChild',
77+
'staticProperty',
78+
false,
79+
];
80+
$data[] = [
81+
'PHPStan\Tests\NetteObjectChild',
82+
'publicProperty',
83+
true,
84+
];
85+
$data[] = [
86+
'PHPStan\Tests\NetteObjectChild',
87+
'protectedProperty',
88+
false,
89+
];
90+
}
91+
return $data;
92+
}
93+
94+
/**
95+
* @dataProvider dataHasProperty
96+
* @param string $className
97+
* @param string $property
98+
* @param bool $result
99+
*/
100+
public function testHasProperty(string $className, string $property, bool $result)
101+
{
102+
$classReflection = $this->mockClassReflection(new \ReflectionClass($className));
103+
$this->assertSame($result, $this->extension->hasProperty($classReflection, $property));
104+
}
105+
106+
private function mockClassReflection(\ReflectionClass $class): ClassReflection
107+
{
108+
$classReflection = $this->createMock(ClassReflection::class);
109+
$classReflection->method('getNativeReflection')->will($this->returnValue($class));
110+
$classReflection->method('hasProperty')->will(
111+
$this->returnCallback(
112+
function (string $property) use ($class): bool {
113+
return $class->hasProperty($property);
114+
}
115+
)
116+
);
117+
$classReflection->method('getProperty')->will(
118+
$this->returnCallback(
119+
function (string $property) use ($class): PropertyReflection {
120+
return $this->mockPropertyReflection($class->getProperty($property));
121+
}
122+
)
123+
);
124+
$classReflection->method('hasMethod')->will(
125+
$this->returnCallback(
126+
function (string $method) use ($class): bool {
127+
return $class->hasMethod($method);
128+
}
129+
)
130+
);
131+
$classReflection->method('getMethod')->will(
132+
$this->returnCallback(
133+
function (string $method) use ($class): MethodReflection {
134+
return $this->mockMethodReflection($class->getMethod($method));
135+
}
136+
)
137+
);
138+
139+
return $classReflection;
140+
}
141+
142+
private function mockMethodReflection(\ReflectionMethod $method): MethodReflection
143+
{
144+
$methodReflection = $this->createMock(MethodReflection::class);
145+
$methodReflection->method('isPublic')->will($this->returnValue($method->isPublic()));
146+
$methodReflection->method('isStatic')->will($this->returnValue($method->isStatic()));
147+
return $methodReflection;
148+
}
149+
150+
private function mockPropertyReflection(\ReflectionProperty $property): PropertyReflection
151+
{
152+
$propertyReflection = $this->createMock(PropertyReflection::class);
153+
$propertyReflection->method('isPublic')->will($this->returnValue($property->isPublic()));
154+
return $propertyReflection;
155+
}
156+
157+
}

tests/notAutoloaded/NetteObjectChild.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,25 @@
44
class NetteObjectChild extends \Nette\Object
55
{
66

7+
/** @var callable[] */
8+
public $onPublicEvent = [];
9+
10+
/** @var callable[] */
11+
protected $onProtectedEvent = [];
12+
13+
public static function getStaticProperty(): string
14+
{
15+
return 'static';
16+
}
17+
18+
public function getPublicProperty(): string
19+
{
20+
return 'public';
21+
}
22+
23+
protected function getProtectedProperty(): string
24+
{
25+
return 'protected';
26+
}
27+
728
}

tests/notAutoloaded/SmartObjectChild.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,10 @@ class SmartObjectChild
66

77
use \Nette\SmartObject;
88

9+
/** @var callable[] */
10+
public $onPublicEvent = [];
11+
12+
/** @var callable[] */
13+
protected $onProtectedEvent = [];
14+
915
}

0 commit comments

Comments
 (0)