Skip to content

Commit 2c57d42

Browse files
committed
ForbidCheckedExceptionInCallableRule: replace immediatelyCalledCallables with native param-immediately-invoked-callable
1 parent bcfea5b commit 2c57d42

File tree

15 files changed

+405
-928
lines changed

15 files changed

+405
-928
lines changed

README.md

Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -49,25 +49,6 @@ parameters:
4949
blacklist: ['(array)', '(object)', '(unset)']
5050
forbidCheckedExceptionInCallable:
5151
enabled: true
52-
immediatelyCalledCallables:
53-
array_reduce: 1
54-
array_intersect_ukey: 2
55-
array_uintersect: 2
56-
array_uintersect_assoc: 2
57-
array_intersect_uassoc: 2
58-
array_uintersect_uassoc: [2, 3]
59-
array_diff_ukey: 2
60-
array_udiff: 2
61-
array_udiff_assoc: 2
62-
array_diff_uassoc: 2
63-
array_udiff_uassoc: [2, 3]
64-
array_filter: 1
65-
array_map: 0
66-
array_walk_recursive: 1
67-
array_walk: 1
68-
uasort: 1
69-
uksort: 1
70-
usort: 1
7152
allowedCheckedExceptionCallables: []
7253
forbidCheckedExceptionInYieldingMethod:
7354
enabled: true
@@ -345,19 +326,14 @@ parameters:
345326

346327
### forbidCheckedExceptionInCallable
347328
- 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
348-
- 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 (!)
349-
- By default, native functions like `array_map` are present. So it is recommended not to overwrite the defaults here (by `!` char).
329+
- 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))
350330
- 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
351331
- It ignores [implicitly thrown Throwable](https://phpstan.org/blog/bring-your-exceptions-under-control#what-does-absent-%40throws-above-a-function-mean%3F)
352332

353333
```neon
354334
parameters:
355335
shipmonkRules:
356336
forbidCheckedExceptionInCallable:
357-
immediatelyCalledCallables:
358-
'Doctrine\ORM\EntityManager::transactional': 0 # 0 is argument index where the closure appears, you can use list if needed
359-
'Symfony\Contracts\Cache\CacheInterface::get': 1
360-
'Acme\my_custom_function': 0
361337
allowedCheckedExceptionCallables:
362338
'Symfony\Component\Console\Question::setValidator': 0 # symfony automatically converts all thrown exceptions to error output, so it is safe to throw anything here
363339
```
@@ -378,16 +354,26 @@ parameters:
378354

379355

380356
```php
357+
class TransactionManager {
358+
/**
359+
* @param-immediately-invoked-callable $callback
360+
*/
361+
public function transactional(callable $callback): void {
362+
// ...
363+
$callback();
364+
// ...
365+
}
366+
}
367+
381368
class UserEditFacade
382369
{
383370
/**
384371
* @throws UserNotFoundException
385-
* ^ This throws would normally be reported as never thrown in native phpstan, but we know the closure is immediately called
386372
*/
387373
public function updateUserEmail(UserId $userId, Email $email): void
388374
{
389-
$this->entityManager->transactional(function () use ($userId, $email) {
390-
$user = $this->userRepository->get($userId); // throws checked UserNotFoundException
375+
$this->transactionManager->transactional(function () use ($userId, $email) {
376+
$user = $this->userRepository->get($userId); // can throw checked UserNotFoundException
391377
$user->updateEmail($email);
392378
})
393379
}

composer.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@
3434
"ShipMonk\\PHPStan\\": "tests/"
3535
},
3636
"classmap": [
37-
"tests/Rule/data",
38-
"tests/Extension/data"
37+
"tests/Rule/data"
3938
]
4039
},
4140
"config": {

composer.lock

Lines changed: 5 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rules.neon

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -28,25 +28,6 @@ parameters:
2828
blacklist: ['(array)', '(object)', '(unset)']
2929
forbidCheckedExceptionInCallable:
3030
enabled: true
31-
immediatelyCalledCallables:
32-
array_reduce: 1
33-
array_intersect_ukey: 2
34-
array_uintersect: 2
35-
array_uintersect_assoc: 2
36-
array_intersect_uassoc: 2
37-
array_uintersect_uassoc: [2, 3]
38-
array_diff_ukey: 2
39-
array_udiff: 2
40-
array_udiff_assoc: 2
41-
array_diff_uassoc: 2
42-
array_udiff_uassoc: [2, 3]
43-
array_filter: 1
44-
array_map: 0
45-
array_walk_recursive: 1
46-
array_walk: 1
47-
uasort: 1
48-
uksort: 1
49-
usort: 1
5031
allowedCheckedExceptionCallables: []
5132
forbidCheckedExceptionInYieldingMethod:
5233
enabled: true
@@ -143,7 +124,6 @@ parametersSchema:
143124
])
144125
forbidCheckedExceptionInCallable: structure([
145126
enabled: bool()
146-
immediatelyCalledCallables: arrayOf(anyOf(listOf(int()), int()), string())
147127
allowedCheckedExceptionCallables: arrayOf(anyOf(listOf(int()), int()), string())
148128
])
149129
forbidCheckedExceptionInYieldingMethod: structure([
@@ -298,8 +278,6 @@ conditionalTags:
298278
ShipMonk\PHPStan\Rule\UselessPrivatePropertyNullabilityRule:
299279
phpstan.rules.rule: %shipmonkRules.uselessPrivatePropertyNullability.enabled%
300280

301-
ShipMonk\PHPStan\Visitor\ImmediatelyCalledCallableVisitor:
302-
phpstan.parser.richParserNodeVisitor: %shipmonkRules.forbidCheckedExceptionInCallable.enabled%
303281
ShipMonk\PHPStan\Visitor\UnusedExceptionVisitor:
304282
phpstan.parser.richParserNodeVisitor: %shipmonkRules.forbidUnusedException.enabled%
305283
ShipMonk\PHPStan\Visitor\UnusedMatchVisitor:
@@ -309,11 +287,6 @@ conditionalTags:
309287
ShipMonk\PHPStan\Visitor\ClassPropertyAssignmentVisitor:
310288
phpstan.parser.richParserNodeVisitor: %shipmonkRules.uselessPrivatePropertyNullability.enabled%
311289

312-
ShipMonk\PHPStan\Extension\ImmediatelyCalledCallableThrowTypeExtension:
313-
phpstan.dynamicFunctionThrowTypeExtension: %shipmonkRules.forbidCheckedExceptionInCallable.enabled%
314-
phpstan.dynamicMethodThrowTypeExtension: %shipmonkRules.forbidCheckedExceptionInCallable.enabled%
315-
phpstan.dynamicStaticMethodThrowTypeExtension: %shipmonkRules.forbidCheckedExceptionInCallable.enabled%
316-
317290
services:
318291
-
319292
class: ShipMonk\PHPStan\Rule\AllowComparingOnlyComparableTypesRule
@@ -348,7 +321,6 @@ services:
348321
-
349322
class: ShipMonk\PHPStan\Rule\ForbidCheckedExceptionInCallableRule
350323
arguments:
351-
immediatelyCalledCallables: %shipmonkRules.forbidCheckedExceptionInCallable.immediatelyCalledCallables%
352324
allowedCheckedExceptionCallables: %shipmonkRules.forbidCheckedExceptionInCallable.allowedCheckedExceptionCallables%
353325
-
354326
class: ShipMonk\PHPStan\Rule\ForbidCheckedExceptionInYieldingMethodRule
@@ -418,11 +390,6 @@ services:
418390
class: ShipMonk\PHPStan\Rule\RequirePreviousExceptionPassRule
419391
arguments:
420392
reportEvenIfExceptionIsNotAcceptableByRethrownOne: %shipmonkRules.requirePreviousExceptionPass.reportEvenIfExceptionIsNotAcceptableByRethrownOne%
421-
-
422-
class: ShipMonk\PHPStan\Visitor\ImmediatelyCalledCallableVisitor
423-
arguments:
424-
immediatelyCalledCallables: %shipmonkRules.forbidCheckedExceptionInCallable.immediatelyCalledCallables%
425-
allowedCheckedExceptionCallables: %shipmonkRules.forbidCheckedExceptionInCallable.allowedCheckedExceptionCallables%
426393
-
427394
class: ShipMonk\PHPStan\Visitor\UnusedExceptionVisitor
428395
-
@@ -431,8 +398,3 @@ services:
431398
class: ShipMonk\PHPStan\Visitor\TopLevelConstructorPropertyFetchMarkingVisitor
432399
-
433400
class: ShipMonk\PHPStan\Visitor\ClassPropertyAssignmentVisitor
434-
435-
-
436-
class: ShipMonk\PHPStan\Extension\ImmediatelyCalledCallableThrowTypeExtension
437-
arguments:
438-
immediatelyCalledCallables: %shipmonkRules.forbidCheckedExceptionInCallable.immediatelyCalledCallables%

0 commit comments

Comments
 (0)