Skip to content

Commit a125304

Browse files
committed
ExceptionTypeResolver as an interface allowing for custom implementations
1 parent fcb5c12 commit a125304

File tree

6 files changed

+130
-112
lines changed

6 files changed

+130
-112
lines changed

conf/config.neon

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -750,12 +750,14 @@ services:
750750
treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain%
751751

752752
-
753-
class: PHPStan\Rules\Exceptions\ExceptionTypeResolver
753+
class: PHPStan\Rules\Exceptions\DefaultExceptionTypeResolver
754754
arguments:
755755
uncheckedExceptionRegexes: %exceptions.uncheckedExceptionRegexes%
756756
uncheckedExceptionClasses: %exceptions.uncheckedExceptionClasses%
757757
checkedExceptionRegexes: %exceptions.checkedExceptionRegexes%
758758
checkedExceptionClasses: %exceptions.checkedExceptionClasses%
759+
autowired:
760+
- PHPStan\Rules\Exceptions\DefaultExceptionTypeResolver
759761

760762
-
761763
class: PHPStan\Rules\Exceptions\MissingCheckedExceptionInFunctionThrowsRule
@@ -765,6 +767,8 @@ services:
765767

766768
-
767769
class: PHPStan\Rules\Exceptions\MissingCheckedExceptionInThrowsCheck
770+
arguments:
771+
exceptionTypeResolver: @exceptionTypeResolver
768772

769773
-
770774
class: PHPStan\Rules\Exceptions\TooWideFunctionThrowTypeRule
@@ -1355,6 +1359,10 @@ services:
13551359
- phpstan.broker.dynamicMethodReturnTypeExtension
13561360
- phpstan.broker.dynamicStaticMethodReturnTypeExtension
13571361

1362+
exceptionTypeResolver:
1363+
class: PHPStan\Rules\Exceptions\ExceptionTypeResolver
1364+
factory: @PHPStan\Rules\Exceptions\DefaultExceptionTypeResolver
1365+
13581366
typeSpecifier:
13591367
class: PHPStan\Analyser\TypeSpecifier
13601368
factory: @typeSpecifierFactory::create
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Exceptions;
4+
5+
use Nette\Utils\Strings;
6+
use PHPStan\Reflection\ReflectionProvider;
7+
8+
class DefaultExceptionTypeResolver implements ExceptionTypeResolver
9+
{
10+
11+
private ReflectionProvider $reflectionProvider;
12+
13+
/** @var string[] */
14+
private array $uncheckedExceptionRegexes;
15+
16+
/** @var string[] */
17+
private array $uncheckedExceptionClasses;
18+
19+
/** @var string[] */
20+
private array $checkedExceptionRegexes;
21+
22+
/** @var string[] */
23+
private array $checkedExceptionClasses;
24+
25+
/**
26+
* @param ReflectionProvider $reflectionProvider
27+
* @param string[] $uncheckedExceptionRegexes
28+
* @param string[] $uncheckedExceptionClasses
29+
* @param string[] $checkedExceptionRegexes
30+
* @param string[] $checkedExceptionClasses
31+
*/
32+
public function __construct(
33+
ReflectionProvider $reflectionProvider,
34+
array $uncheckedExceptionRegexes,
35+
array $uncheckedExceptionClasses,
36+
array $checkedExceptionRegexes,
37+
array $checkedExceptionClasses
38+
)
39+
{
40+
$this->reflectionProvider = $reflectionProvider;
41+
$this->uncheckedExceptionRegexes = $uncheckedExceptionRegexes;
42+
$this->uncheckedExceptionClasses = $uncheckedExceptionClasses;
43+
$this->checkedExceptionRegexes = $checkedExceptionRegexes;
44+
$this->checkedExceptionClasses = $checkedExceptionClasses;
45+
}
46+
47+
public function isCheckedException(string $className): bool
48+
{
49+
foreach ($this->uncheckedExceptionRegexes as $regex) {
50+
if (Strings::match($className, $regex) !== null) {
51+
return false;
52+
}
53+
}
54+
55+
foreach ($this->uncheckedExceptionClasses as $uncheckedExceptionClass) {
56+
if ($className === $uncheckedExceptionClass) {
57+
return false;
58+
}
59+
}
60+
61+
if (!$this->reflectionProvider->hasClass($className)) {
62+
return $this->isCheckedExceptionInternal($className);
63+
}
64+
65+
$classReflection = $this->reflectionProvider->getClass($className);
66+
foreach ($this->uncheckedExceptionClasses as $uncheckedExceptionClass) {
67+
if ($classReflection->getName() === $uncheckedExceptionClass) {
68+
return false;
69+
}
70+
71+
if (!$classReflection->isSubclassOf($uncheckedExceptionClass)) {
72+
continue;
73+
}
74+
75+
return false;
76+
}
77+
78+
return $this->isCheckedExceptionInternal($className);
79+
}
80+
81+
private function isCheckedExceptionInternal(string $className): bool
82+
{
83+
foreach ($this->checkedExceptionRegexes as $regex) {
84+
if (Strings::match($className, $regex) !== null) {
85+
return true;
86+
}
87+
}
88+
89+
foreach ($this->checkedExceptionClasses as $checkedExceptionClass) {
90+
if ($className === $checkedExceptionClass) {
91+
return true;
92+
}
93+
}
94+
95+
if (!$this->reflectionProvider->hasClass($className)) {
96+
return count($this->checkedExceptionRegexes) === 0 && count($this->checkedExceptionClasses) === 0;
97+
}
98+
99+
$classReflection = $this->reflectionProvider->getClass($className);
100+
foreach ($this->checkedExceptionClasses as $checkedExceptionClass) {
101+
if ($classReflection->getName() === $checkedExceptionClass) {
102+
return true;
103+
}
104+
105+
if (!$classReflection->isSubclassOf($checkedExceptionClass)) {
106+
continue;
107+
}
108+
109+
return true;
110+
}
111+
112+
return count($this->checkedExceptionRegexes) === 0 && count($this->checkedExceptionClasses) === 0;
113+
}
114+
115+
}

src/Rules/Exceptions/ExceptionTypeResolver.php

Lines changed: 2 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -2,114 +2,9 @@
22

33
namespace PHPStan\Rules\Exceptions;
44

5-
use Nette\Utils\Strings;
6-
use PHPStan\Reflection\ReflectionProvider;
7-
8-
class ExceptionTypeResolver
5+
interface ExceptionTypeResolver
96
{
107

11-
private ReflectionProvider $reflectionProvider;
12-
13-
/** @var string[] */
14-
private array $uncheckedExceptionRegexes;
15-
16-
/** @var string[] */
17-
private array $uncheckedExceptionClasses;
18-
19-
/** @var string[] */
20-
private array $checkedExceptionRegexes;
21-
22-
/** @var string[] */
23-
private array $checkedExceptionClasses;
24-
25-
/**
26-
* @param ReflectionProvider $reflectionProvider
27-
* @param string[] $uncheckedExceptionRegexes
28-
* @param string[] $uncheckedExceptionClasses
29-
* @param string[] $checkedExceptionRegexes
30-
* @param string[] $checkedExceptionClasses
31-
*/
32-
public function __construct(
33-
ReflectionProvider $reflectionProvider,
34-
array $uncheckedExceptionRegexes,
35-
array $uncheckedExceptionClasses,
36-
array $checkedExceptionRegexes,
37-
array $checkedExceptionClasses
38-
)
39-
{
40-
$this->reflectionProvider = $reflectionProvider;
41-
$this->uncheckedExceptionRegexes = $uncheckedExceptionRegexes;
42-
$this->uncheckedExceptionClasses = $uncheckedExceptionClasses;
43-
$this->checkedExceptionRegexes = $checkedExceptionRegexes;
44-
$this->checkedExceptionClasses = $checkedExceptionClasses;
45-
}
46-
47-
public function isCheckedException(string $className): bool
48-
{
49-
foreach ($this->uncheckedExceptionRegexes as $regex) {
50-
if (Strings::match($className, $regex) !== null) {
51-
return false;
52-
}
53-
}
54-
55-
foreach ($this->uncheckedExceptionClasses as $uncheckedExceptionClass) {
56-
if ($className === $uncheckedExceptionClass) {
57-
return false;
58-
}
59-
}
60-
61-
if (!$this->reflectionProvider->hasClass($className)) {
62-
return $this->isCheckedExceptionInternal($className);
63-
}
64-
65-
$classReflection = $this->reflectionProvider->getClass($className);
66-
foreach ($this->uncheckedExceptionClasses as $uncheckedExceptionClass) {
67-
if ($classReflection->getName() === $uncheckedExceptionClass) {
68-
return false;
69-
}
70-
71-
if (!$classReflection->isSubclassOf($uncheckedExceptionClass)) {
72-
continue;
73-
}
74-
75-
return false;
76-
}
77-
78-
return $this->isCheckedExceptionInternal($className);
79-
}
80-
81-
private function isCheckedExceptionInternal(string $className): bool
82-
{
83-
foreach ($this->checkedExceptionRegexes as $regex) {
84-
if (Strings::match($className, $regex) !== null) {
85-
return true;
86-
}
87-
}
88-
89-
foreach ($this->checkedExceptionClasses as $checkedExceptionClass) {
90-
if ($className === $checkedExceptionClass) {
91-
return true;
92-
}
93-
}
94-
95-
if (!$this->reflectionProvider->hasClass($className)) {
96-
return count($this->checkedExceptionRegexes) === 0 && count($this->checkedExceptionClasses) === 0;
97-
}
98-
99-
$classReflection = $this->reflectionProvider->getClass($className);
100-
foreach ($this->checkedExceptionClasses as $checkedExceptionClass) {
101-
if ($classReflection->getName() === $checkedExceptionClass) {
102-
return true;
103-
}
104-
105-
if (!$classReflection->isSubclassOf($checkedExceptionClass)) {
106-
continue;
107-
}
108-
109-
return true;
110-
}
111-
112-
return count($this->checkedExceptionRegexes) === 0 && count($this->checkedExceptionClasses) === 0;
113-
}
8+
public function isCheckedException(string $className): bool;
1149

11510
}

tests/PHPStan/Rules/Exceptions/ExceptionTypeResolverTest.php renamed to tests/PHPStan/Rules/Exceptions/DefaultExceptionTypeResolverTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
use PHPStan\Testing\TestCase;
66

7-
class ExceptionTypeResolverTest extends TestCase
7+
class DefaultExceptionTypeResolverTest extends TestCase
88
{
99

1010
public function dataIsCheckedException(): array
@@ -139,7 +139,7 @@ public function testIsCheckedException(
139139
bool $expectedResult
140140
): void
141141
{
142-
$resolver = new ExceptionTypeResolver($this->createBroker(), $uncheckedExceptionRegexes, $uncheckedExceptionClasses, $checkedExceptionRegexes, $checkedExceptionClasses);
142+
$resolver = new DefaultExceptionTypeResolver($this->createBroker(), $uncheckedExceptionRegexes, $uncheckedExceptionClasses, $checkedExceptionRegexes, $checkedExceptionClasses);
143143
$this->assertSame($expectedResult, $resolver->isCheckedException($className));
144144
}
145145

tests/PHPStan/Rules/Exceptions/MissingCheckedExceptionInFunctionThrowsRuleTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class MissingCheckedExceptionInFunctionThrowsRuleTest extends RuleTestCase
1414
protected function getRule(): Rule
1515
{
1616
return new MissingCheckedExceptionInFunctionThrowsRule(
17-
new MissingCheckedExceptionInThrowsCheck(new ExceptionTypeResolver(
17+
new MissingCheckedExceptionInThrowsCheck(new DefaultExceptionTypeResolver(
1818
$this->createReflectionProvider(),
1919
[],
2020
[\PHPStan\ShouldNotHappenException::class],

tests/PHPStan/Rules/Exceptions/MissingCheckedExceptionInMethodThrowsRuleTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class MissingCheckedExceptionInMethodThrowsRuleTest extends RuleTestCase
1414
protected function getRule(): Rule
1515
{
1616
return new MissingCheckedExceptionInMethodThrowsRule(
17-
new MissingCheckedExceptionInThrowsCheck(new ExceptionTypeResolver(
17+
new MissingCheckedExceptionInThrowsCheck(new DefaultExceptionTypeResolver(
1818
$this->createReflectionProvider(),
1919
[],
2020
[\PHPStan\ShouldNotHappenException::class],

0 commit comments

Comments
 (0)