1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\Rules\Exceptions;
4:
5: use Nette\Utils\Strings;
6: use PHPStan\Analyser\Scope;
7: use PHPStan\Reflection\ReflectionProvider;
8: use function count;
9:
10: /**
11: * @api
12: */
13: final class DefaultExceptionTypeResolver implements ExceptionTypeResolver
14: {
15:
16: /**
17: * @param string[] $uncheckedExceptionRegexes
18: * @param string[] $uncheckedExceptionClasses
19: * @param string[] $checkedExceptionRegexes
20: * @param string[] $checkedExceptionClasses
21: */
22: public function __construct(
23: private ReflectionProvider $reflectionProvider,
24: private array $uncheckedExceptionRegexes,
25: private array $uncheckedExceptionClasses,
26: private array $checkedExceptionRegexes,
27: private array $checkedExceptionClasses,
28: )
29: {
30: }
31:
32: public function isCheckedException(string $className, Scope $scope): bool
33: {
34: foreach ($this->uncheckedExceptionRegexes as $regex) {
35: if (Strings::match($className, $regex) !== null) {
36: return false;
37: }
38: }
39:
40: foreach ($this->uncheckedExceptionClasses as $uncheckedExceptionClass) {
41: if ($className === $uncheckedExceptionClass) {
42: return false;
43: }
44: }
45:
46: if (!$this->reflectionProvider->hasClass($className)) {
47: return $this->isCheckedExceptionInternal($className);
48: }
49:
50: $classReflection = $this->reflectionProvider->getClass($className);
51: foreach ($this->uncheckedExceptionClasses as $uncheckedExceptionClass) {
52: if (!$classReflection->is($uncheckedExceptionClass)) {
53: continue;
54: }
55:
56: return false;
57: }
58:
59: return $this->isCheckedExceptionInternal($className);
60: }
61:
62: private function isCheckedExceptionInternal(string $className): bool
63: {
64: foreach ($this->checkedExceptionRegexes as $regex) {
65: if (Strings::match($className, $regex) !== null) {
66: return true;
67: }
68: }
69:
70: foreach ($this->checkedExceptionClasses as $checkedExceptionClass) {
71: if ($className === $checkedExceptionClass) {
72: return true;
73: }
74: }
75:
76: if (!$this->reflectionProvider->hasClass($className)) {
77: return count($this->checkedExceptionRegexes) === 0 && count($this->checkedExceptionClasses) === 0;
78: }
79:
80: $classReflection = $this->reflectionProvider->getClass($className);
81: foreach ($this->checkedExceptionClasses as $checkedExceptionClass) {
82: if (!$classReflection->is($checkedExceptionClass)) {
83: continue;
84: }
85:
86: return true;
87: }
88:
89: return count($this->checkedExceptionRegexes) === 0 && count($this->checkedExceptionClasses) === 0;
90: }
91:
92: }
93: