Skip to content

Commit 4c17d37

Browse files
committed
Validate checkedExceptionClasses config
Validate that class names configured in checkedExceptionClasses and uncheckedExceptionClasses actually exist, preventing silent misconfiguration. Gated behind bleedingEdge feature toggle. Also removes non-existent exception classes from build/phpstan.neon. Co-Authored-By: Claude Code
1 parent 38036bf commit 4c17d37

8 files changed

Lines changed: 50 additions & 8 deletions

build/phpstan.neon

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ parameters:
4343
- 'PHPStan\ShouldNotHappenException'
4444
- 'Symfony\Component\Console\Exception\InvalidArgumentException'
4545
- 'PHPStan\BetterReflection\SourceLocator\Exception\InvalidFileLocation'
46-
- 'PHPStan\BetterReflection\SourceLocator\Exception\InvalidArgumentException'
4746
- 'Symfony\Component\Finder\Exception\DirectoryNotFoundException'
4847
- 'InvalidArgumentException'
4948
- 'PHPStan\DependencyInjection\ParameterNotFoundException'
@@ -69,7 +68,6 @@ parameters:
6968
- 'PHPStan\Reflection\MissingStaticAccessorInstanceException'
7069
- 'LogicException'
7170
- 'Error'
72-
- 'PHPStan\Analyser\Generator\TrampolineException'
7371
check:
7472
missingCheckedExceptionInThrows: true
7573
tooWideThrowType: true

src/DependencyInjection/ContainerFactory.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Nette\DI\Definitions\Statement;
88
use Nette\DI\Extensions\ExtensionsExtension;
99
use Nette\DI\Helpers;
10+
use Nette\DI\InvalidConfigurationException;
1011
use Nette\Schema\Context as SchemaContext;
1112
use Nette\Schema\Elements\AnyOf;
1213
use Nette\Schema\Elements\Structure;
@@ -161,6 +162,7 @@ public function create(
161162

162163
$container = $configurator->createContainer()->getByType(Container::class);
163164
$this->validateParameters($container->getParameters(), $projectConfig['parametersSchema']);
165+
$this->validateExceptionClasses($container->getByType(ReflectionProvider::class), $container->getParameters());
164166
self::postInitializeContainer($container);
165167

166168
return $container;
@@ -364,6 +366,30 @@ private function validateParameters(array $parameters, array $parametersSchema):
364366
}
365367
}
366368

369+
/**
370+
* @param array<mixed> $parameters
371+
*/
372+
private function validateExceptionClasses(ReflectionProvider $reflectionProvider, array $parameters): void
373+
{
374+
if (
375+
!array_key_exists('featureToggles', $parameters)
376+
|| !is_array($parameters['featureToggles'])
377+
|| !(bool) $parameters['featureToggles']['bleedingEdge']
378+
) {
379+
return;
380+
}
381+
382+
foreach (['checkedExceptionClasses', 'uncheckedExceptionClasses'] as $parameterName) {
383+
foreach ($parameters['exceptions'][$parameterName] ?? [] as $className) {
384+
if ($reflectionProvider->hasClass($className)) {
385+
continue;
386+
}
387+
388+
throw new InvalidConfigurationException(sprintf('Class %s configured in exceptions.%s does not exist.', $className, $parameterName));
389+
}
390+
}
391+
}
392+
367393
/**
368394
* @param Statement[] $statements
369395
*/

tests/PHPStan/Rules/Exceptions/ThrowsVoidFunctionWithExplicitThrowPointRuleTest.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use PHPStan\Rules\Rule;
66
use PHPStan\Testing\RuleTestCase;
77
use PHPUnit\Framework\Attributes\DataProvider;
8+
use ThrowsVoidFunction\DifferentException;
89
use ThrowsVoidFunction\MyException;
910

1011
/**
@@ -39,7 +40,7 @@ public static function dataRule(): array
3940
],
4041
[
4142
false,
42-
['DifferentException'],
43+
[DifferentException::class],
4344
[
4445
[
4546
'Function ThrowsVoidFunction\foo() throws exception ThrowsVoidFunction\MyException but the PHPDoc contains @throws void.',
@@ -54,7 +55,7 @@ public static function dataRule(): array
5455
],
5556
[
5657
true,
57-
['DifferentException'],
58+
[DifferentException::class],
5859
[
5960
[
6061
'Function ThrowsVoidFunction\foo() throws exception ThrowsVoidFunction\MyException but the PHPDoc contains @throws void.',

tests/PHPStan/Rules/Exceptions/ThrowsVoidMethodWithExplicitThrowPointRuleTest.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use PHPStan\Testing\RuleTestCase;
77
use PHPUnit\Framework\Attributes\DataProvider;
88
use PHPUnit\Framework\Attributes\RequiresPhp;
9+
use ThrowsVoidMethod\DifferentException;
910
use ThrowsVoidMethod\MyException;
1011
use UnhandledMatchError;
1112
use ValueError;
@@ -42,7 +43,7 @@ public static function dataRule(): array
4243
],
4344
[
4445
false,
45-
['DifferentException'],
46+
[DifferentException::class],
4647
[
4748
[
4849
'Method ThrowsVoidMethod\Foo::doFoo() throws exception ThrowsVoidMethod\MyException but the PHPDoc contains @throws void.',
@@ -57,7 +58,7 @@ public static function dataRule(): array
5758
],
5859
[
5960
true,
60-
['DifferentException'],
61+
[DifferentException::class],
6162
[
6263
[
6364
'Method ThrowsVoidMethod\Foo::doFoo() throws exception ThrowsVoidMethod\MyException but the PHPDoc contains @throws void.',

tests/PHPStan/Rules/Exceptions/ThrowsVoidPropertyHookWithExplicitThrowPointRuleTest.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use PHPStan\Testing\RuleTestCase;
77
use PHPUnit\Framework\Attributes\DataProvider;
88
use PHPUnit\Framework\Attributes\RequiresPhp;
9+
use ThrowsVoidPropertyHook\DifferentException;
910

1011
/**
1112
* @extends RuleTestCase<ThrowsVoidPropertyHookWithExplicitThrowPointRule>
@@ -39,7 +40,7 @@ public static function dataRule(): array
3940
],
4041
[
4142
false,
42-
['DifferentException'],
43+
[DifferentException::class],
4344
[
4445
[
4546
'Get hook for property ThrowsVoidPropertyHook\Foo::$i throws exception ThrowsVoidPropertyHook\MyException but the PHPDoc contains @throws void.',
@@ -58,7 +59,7 @@ public static function dataRule(): array
5859
],
5960
[
6061
true,
61-
['DifferentException'],
62+
[DifferentException::class],
6263
[
6364
[
6465
'Get hook for property ThrowsVoidPropertyHook\Foo::$i throws exception ThrowsVoidPropertyHook\MyException but the PHPDoc contains @throws void.',

tests/PHPStan/Rules/Exceptions/data/throws-void-function.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,8 @@ function foo(): void
1414
{
1515
throw new MyException();
1616
}
17+
18+
class DifferentException extends \Exception
19+
{
20+
21+
}

tests/PHPStan/Rules/Exceptions/data/throws-void-method.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,8 @@ public function doFoo(): void
2020

2121

2222
}
23+
24+
class DifferentException extends \Exception
25+
{
26+
27+
}

tests/PHPStan/Rules/Exceptions/data/throws-void-property-hook.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,8 @@ class Foo
2727
}
2828

2929
}
30+
31+
class DifferentException extends \Exception
32+
{
33+
34+
}

0 commit comments

Comments
 (0)