Skip to content

Commit cd46996

Browse files
adaamzondrejmirtes
authored andcommitted
Check whether property has typehint
1 parent 1b144e3 commit cd46996

File tree

4 files changed

+120
-0
lines changed

4 files changed

+120
-0
lines changed

Diff for: rules.neon

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ rules:
1717
- PHPStan\Rules\Methods\MissingMethodParameterTypehintRule
1818
- PHPStan\Rules\Methods\MissingMethodReturnTypehintRule
1919
- PHPStan\Rules\Methods\WrongCaseOfInheritedMethodRule
20+
- PHPStan\Rules\Properties\MissingPropertyTypehintRule
2021
- PHPStan\Rules\StrictCalls\DynamicCallOnStaticMethodsRule
2122
- PHPStan\Rules\StrictCalls\StrictFunctionCallsRule
2223
- PHPStan\Rules\SwitchConditions\MatchingTypeInSwitchCaseConditionRule

Diff for: src/Rules/Properties/MissingPropertyTypehintRule.php

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Properties;
4+
5+
use PhpParser\Node;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\Reflection\PropertyReflection;
8+
use PHPStan\Type\MixedType;
9+
10+
final class MissingPropertyTypehintRule implements \PHPStan\Rules\Rule
11+
{
12+
13+
/**
14+
* @return string Class implementing \PhpParser\Node
15+
*/
16+
public function getNodeType(): string
17+
{
18+
return \PhpParser\Node\Stmt\PropertyProperty::class;
19+
}
20+
21+
/**
22+
* @param \PhpParser\Node\Stmt\PropertyProperty $node
23+
* @param \PHPStan\Analyser\Scope $scope
24+
*
25+
* @return string[] errors
26+
*/
27+
public function processNode(Node $node, Scope $scope): array
28+
{
29+
if (!$scope->isInClass()) {
30+
throw new \PHPStan\ShouldNotHappenException();
31+
}
32+
33+
$propertyReflection = $scope->getClassReflection()->getNativeProperty($node->name);
34+
35+
$messages = [];
36+
37+
$message = $this->checkPropertyType($node->name, $propertyReflection);
38+
if ($message !== null) {
39+
$messages[] = $message;
40+
}
41+
42+
return $messages;
43+
}
44+
45+
private function checkPropertyType(string $propertyName, PropertyReflection $propertyReflection): ?string
46+
{
47+
$returnType = $propertyReflection->getType();
48+
49+
if ($returnType instanceof MixedType && !$returnType->isExplicitMixed()) {
50+
return sprintf(
51+
'Property %s::$%s has no typehint specified',
52+
$propertyReflection->getDeclaringClass()->getName(),
53+
$propertyName
54+
);
55+
}
56+
57+
return null;
58+
}
59+
60+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Properties;
4+
5+
class MissingPropertyTypehintRuleTest extends \PHPStan\Testing\RuleTestCase
6+
{
7+
8+
protected function getRule(): \PHPStan\Rules\Rule
9+
{
10+
return new MissingPropertyTypehintRule();
11+
}
12+
13+
public function testRule(): void
14+
{
15+
$this->analyse([__DIR__ . '/data/missing-property-typehint.php'], [
16+
[
17+
'Property MissingPropertyTypehint\MyClass::$prop1 has no typehint specified',
18+
7,
19+
],
20+
[
21+
'Property MissingPropertyTypehint\MyClass::$prop2 has no typehint specified',
22+
9,
23+
],
24+
[
25+
'Property MissingPropertyTypehint\MyClass::$prop3 has no typehint specified',
26+
14,
27+
],
28+
]);
29+
}
30+
31+
}
+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace MissingPropertyTypehint;
4+
5+
class MyClass
6+
{
7+
private $prop1;
8+
9+
protected $prop2 = null;
10+
11+
/**
12+
* @var
13+
*/
14+
public $prop3;
15+
}
16+
17+
class ChildClass extends MyClass
18+
{
19+
/**
20+
* @var int
21+
*/
22+
protected $prop1;
23+
24+
/**
25+
* @var null
26+
*/
27+
protected $prop2;
28+
}

0 commit comments

Comments
 (0)