Skip to content

Commit 32723e0

Browse files
phpstan-botclaude
andcommitted
Make string cast throw points dependent on PHP version
__toString() can only throw exceptions since PHP 7.4. Add PhpVersion::throwsOnStringCast() and gate the throw point creation in CastStringHandler on it. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 28b81c7 commit 32723e0

File tree

2 files changed

+20
-11
lines changed

2 files changed

+20
-11
lines changed

src/Analyser/ExprHandler/CastStringHandler.php

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use PHPStan\Analyser\NodeScopeResolver;
1616
use PHPStan\DependencyInjection\AutowiredParameter;
1717
use PHPStan\DependencyInjection\AutowiredService;
18+
use PHPStan\Php\PhpVersion;
1819
use PHPStan\Reflection\InitializerExprTypeResolver;
1920
use PHPStan\Type\NeverType;
2021
use PHPStan\Type\ObjectType;
@@ -31,6 +32,7 @@ final class CastStringHandler implements ExprHandler
3132

3233
public function __construct(
3334
private InitializerExprTypeResolver $initializerExprTypeResolver,
35+
private PhpVersion $phpVersion,
3436
#[AutowiredParameter(ref: '%exceptions.implicitThrows%')]
3537
private bool $implicitThrows,
3638
)
@@ -61,20 +63,22 @@ public function processExpr(NodeScopeResolver $nodeScopeResolver, Stmt $stmt, Ex
6163
);
6264
}
6365

64-
$throwType = $toStringMethod->getThrowType();
65-
if ($throwType === null) {
66-
$returnType = $toStringMethod->getVariants()[0]->getReturnType();
67-
if ($returnType instanceof NeverType && $returnType->isExplicit()) {
68-
$throwType = new ObjectType(Throwable::class);
66+
if ($this->phpVersion->throwsOnStringCast()) {
67+
$throwType = $toStringMethod->getThrowType();
68+
if ($throwType === null) {
69+
$returnType = $toStringMethod->getVariants()[0]->getReturnType();
70+
if ($returnType instanceof NeverType && $returnType->isExplicit()) {
71+
$throwType = new ObjectType(Throwable::class);
72+
}
6973
}
70-
}
7174

72-
if ($throwType !== null) {
73-
if (!$throwType->isVoid()->yes()) {
74-
$throwPoints[] = InternalThrowPoint::createExplicit($scope, $throwType, $expr, true);
75+
if ($throwType !== null) {
76+
if (!$throwType->isVoid()->yes()) {
77+
$throwPoints[] = InternalThrowPoint::createExplicit($scope, $throwType, $expr, true);
78+
}
79+
} elseif ($this->implicitThrows) {
80+
$throwPoints[] = InternalThrowPoint::createImplicit($scope, $expr);
7581
}
76-
} elseif ($this->implicitThrows) {
77-
$throwPoints[] = InternalThrowPoint::createImplicit($scope, $expr);
7882
}
7983
}
8084

src/Php/PhpVersion.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,4 +506,9 @@ public function hasFilterThrowOnFailureConstant(): bool
506506
return $this->versionId >= 80500;
507507
}
508508

509+
public function throwsOnStringCast(): bool
510+
{
511+
return $this->versionId >= 70400;
512+
}
513+
509514
}

0 commit comments

Comments
 (0)