Skip to content

Commit

Permalink
ForbidCheckedExceptionInCallableRule: replace immediatelyCalledCallab…
Browse files Browse the repository at this point in the history
…les with native param-immediately-invoked-callable
  • Loading branch information
janedbal committed May 14, 2024
1 parent 484a1c0 commit 2da5af5
Show file tree
Hide file tree
Showing 15 changed files with 402 additions and 934 deletions.
46 changes: 14 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,29 +49,6 @@ parameters:
blacklist: ['(array)', '(object)', '(unset)']
forbidCheckedExceptionInCallable:
enabled: true
immediatelyCalledCallables:
array_reduce: 1
array_intersect_ukey: 2
array_uintersect: 2
array_uintersect_assoc: 2
array_intersect_uassoc: 2
array_uintersect_uassoc: [2, 3]
array_diff_ukey: 2
array_udiff: 2
array_udiff_assoc: 2
array_diff_uassoc: 2
array_udiff_uassoc: [2, 3]
array_filter: 1
array_map: 0
array_walk_recursive: 1
array_walk: 1
call_user_func: 0
call_user_func_array: 0
forward_static_call: 0
forward_static_call_array: 0
uasort: 1
uksort: 1
usort: 1
allowedCheckedExceptionCallables: []
forbidCheckedExceptionInYieldingMethod:
enabled: true
Expand Down Expand Up @@ -350,8 +327,7 @@ parameters:

### forbidCheckedExceptionInCallable
- Denies throwing [checked exception](https://phpstan.org/blog/bring-your-exceptions-under-control) in callables (Closures, Arrow functions and First class callables) as those cannot be tracked as checked by PHPStan analysis, because it is unknown when the callable is about to be called
- It allows configuration of functions/methods, where the callable is called immediately, those cases are allowed and are also added to [dynamic throw type extension](https://phpstan.org/developing-extensions/dynamic-throw-type-extensions) which causes those exceptions to be tracked properly in your codebase (!)
- By default, native functions like `array_map` are present. So it is recommended not to overwrite the defaults here (by `!` char).
- It is allowed to throw checked exceptions in immediately called callables (e.g. params marked by `@param-immediately-invoked-callable`, see [docs](https://phpstan.org/writing-php-code/phpdocs-basics#callables))
- It allows configuration of functions/methods, where the callable is handling all thrown exceptions and it is safe to throw anything from there; this basically makes such calls ignored by this rule
- It ignores [implicitly thrown Throwable](https://phpstan.org/blog/bring-your-exceptions-under-control#what-does-absent-%40throws-above-a-function-mean%3F)
- Learn more in 🇨🇿 [talk about checked exceptions in general](https://www.youtube.com/watch?v=UQsP1U0sVZM)
Expand All @@ -360,10 +336,6 @@ parameters:
parameters:
shipmonkRules:
forbidCheckedExceptionInCallable:
immediatelyCalledCallables:
'Doctrine\ORM\EntityManager::transactional': 0 # 0 is argument index where the closure appears, you can use list if needed
'Symfony\Contracts\Cache\CacheInterface::get': 1
'Acme\my_custom_function': 0
allowedCheckedExceptionCallables:
'Symfony\Component\Console\Question::setValidator': 0 # symfony automatically converts all thrown exceptions to error output, so it is safe to throw anything here
```
Expand All @@ -384,16 +356,26 @@ parameters:


```php
class TransactionManager {
/**
* @param-immediately-invoked-callable $callback
*/
public function transactional(callable $callback): void {
// ...
$callback();
// ...
}
}

class UserEditFacade
{
/**
* @throws UserNotFoundException
* ^ This throws would normally be reported as never thrown in native phpstan, but we know the closure is immediately called
*/
public function updateUserEmail(UserId $userId, Email $email): void
{
$this->entityManager->transactional(function () use ($userId, $email) {
$user = $this->userRepository->get($userId); // throws checked UserNotFoundException
$this->transactionManager->transactional(function () use ($userId, $email) {
$user = $this->userRepository->get($userId); // can throw checked UserNotFoundException
$user->updateEmail($email);
})
}
Expand Down
3 changes: 1 addition & 2 deletions composer-dependency-analyser.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,4 @@
require_once('phar://phpstan.phar/preload.php'); // prepends PHPStan's PharAutolaoder to composer's autoloader

return (new Configuration())
->addPathToExclude(__DIR__ . '/tests/Rule/data')
->addPathToExclude(__DIR__ . '/tests/Extension/data');
->addPathToExclude(__DIR__ . '/tests/Rule/data');
3 changes: 1 addition & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@
"ShipMonk\\PHPStan\\": "tests/"
},
"classmap": [
"tests/Rule/data",
"tests/Extension/data"
"tests/Rule/data"
]
},
"config": {
Expand Down
42 changes: 0 additions & 42 deletions rules.neon
Original file line number Diff line number Diff line change
Expand Up @@ -28,29 +28,6 @@ parameters:
blacklist: ['(array)', '(object)', '(unset)']
forbidCheckedExceptionInCallable:
enabled: true
immediatelyCalledCallables:
array_reduce: 1
array_intersect_ukey: 2
array_uintersect: 2
array_uintersect_assoc: 2
array_intersect_uassoc: 2
array_uintersect_uassoc: [2, 3]
array_diff_ukey: 2
array_udiff: 2
array_udiff_assoc: 2
array_diff_uassoc: 2
array_udiff_uassoc: [2, 3]
array_filter: 1
array_map: 0
array_walk_recursive: 1
array_walk: 1
call_user_func: 0
call_user_func_array: 0
forward_static_call: 0
forward_static_call_array: 0
uasort: 1
uksort: 1
usort: 1
allowedCheckedExceptionCallables: []
forbidCheckedExceptionInYieldingMethod:
enabled: true
Expand Down Expand Up @@ -147,7 +124,6 @@ parametersSchema:
])
forbidCheckedExceptionInCallable: structure([
enabled: bool()
immediatelyCalledCallables: arrayOf(anyOf(listOf(int()), int()), string())
allowedCheckedExceptionCallables: arrayOf(anyOf(listOf(int()), int()), string())
])
forbidCheckedExceptionInYieldingMethod: structure([
Expand Down Expand Up @@ -302,8 +278,6 @@ conditionalTags:
ShipMonk\PHPStan\Rule\UselessPrivatePropertyNullabilityRule:
phpstan.rules.rule: %shipmonkRules.uselessPrivatePropertyNullability.enabled%

ShipMonk\PHPStan\Visitor\ImmediatelyCalledCallableVisitor:
phpstan.parser.richParserNodeVisitor: %shipmonkRules.forbidCheckedExceptionInCallable.enabled%
ShipMonk\PHPStan\Visitor\UnusedExceptionVisitor:
phpstan.parser.richParserNodeVisitor: %shipmonkRules.forbidUnusedException.enabled%
ShipMonk\PHPStan\Visitor\UnusedMatchVisitor:
Expand All @@ -313,11 +287,6 @@ conditionalTags:
ShipMonk\PHPStan\Visitor\ClassPropertyAssignmentVisitor:
phpstan.parser.richParserNodeVisitor: %shipmonkRules.uselessPrivatePropertyNullability.enabled%

ShipMonk\PHPStan\Extension\ImmediatelyCalledCallableThrowTypeExtension:
phpstan.dynamicFunctionThrowTypeExtension: %shipmonkRules.forbidCheckedExceptionInCallable.enabled%
phpstan.dynamicMethodThrowTypeExtension: %shipmonkRules.forbidCheckedExceptionInCallable.enabled%
phpstan.dynamicStaticMethodThrowTypeExtension: %shipmonkRules.forbidCheckedExceptionInCallable.enabled%

services:
-
class: ShipMonk\PHPStan\Rule\AllowComparingOnlyComparableTypesRule
Expand Down Expand Up @@ -352,7 +321,6 @@ services:
-
class: ShipMonk\PHPStan\Rule\ForbidCheckedExceptionInCallableRule
arguments:
immediatelyCalledCallables: %shipmonkRules.forbidCheckedExceptionInCallable.immediatelyCalledCallables%
allowedCheckedExceptionCallables: %shipmonkRules.forbidCheckedExceptionInCallable.allowedCheckedExceptionCallables%
-
class: ShipMonk\PHPStan\Rule\ForbidCheckedExceptionInYieldingMethodRule
Expand Down Expand Up @@ -422,11 +390,6 @@ services:
class: ShipMonk\PHPStan\Rule\RequirePreviousExceptionPassRule
arguments:
reportEvenIfExceptionIsNotAcceptableByRethrownOne: %shipmonkRules.requirePreviousExceptionPass.reportEvenIfExceptionIsNotAcceptableByRethrownOne%
-
class: ShipMonk\PHPStan\Visitor\ImmediatelyCalledCallableVisitor
arguments:
immediatelyCalledCallables: %shipmonkRules.forbidCheckedExceptionInCallable.immediatelyCalledCallables%
allowedCheckedExceptionCallables: %shipmonkRules.forbidCheckedExceptionInCallable.allowedCheckedExceptionCallables%
-
class: ShipMonk\PHPStan\Visitor\UnusedExceptionVisitor
-
Expand All @@ -435,8 +398,3 @@ services:
class: ShipMonk\PHPStan\Visitor\TopLevelConstructorPropertyFetchMarkingVisitor
-
class: ShipMonk\PHPStan\Visitor\ClassPropertyAssignmentVisitor

-
class: ShipMonk\PHPStan\Extension\ImmediatelyCalledCallableThrowTypeExtension
arguments:
immediatelyCalledCallables: %shipmonkRules.forbidCheckedExceptionInCallable.immediatelyCalledCallables%
Loading

0 comments on commit 2da5af5

Please sign in to comment.