Skip to content

Commit a72f09c

Browse files
phpstan-botclaudestaabm
authored
Report exceptions thrown from ResultCacheMetaExtension during result cache restore as internal errors (#5853)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Markus Staab <markus.staab@redaxo.de>
1 parent b9cc732 commit a72f09c

11 files changed

Lines changed: 105 additions & 2 deletions

File tree

.github/workflows/e2e-tests.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,17 @@ jobs:
336336
echo "$OUTPUT"
337337
../bashunit -a matches "Note: Using configuration file .+phpstan.neon." "$OUTPUT"
338338
../bashunit -a contains 'Result cache not used because the metadata do not match: metaExtensions' "$OUTPUT"
339+
- script: |
340+
cd e2e/result-cache-meta-extension-throw
341+
composer install
342+
# https://github.com/phpstan/phpstan/issues/14805
343+
# An exception thrown from ResultCacheMetaExtension::getHash() during result cache
344+
# restore must fail the run with a non-zero exit code - even when a bootstrap file
345+
# installs a global exception handler that would otherwise swallow it into exit 0.
346+
OUTPUT=$(../bashunit -a exit_code "1" "../../bin/phpstan --error-format=raw")
347+
echo "$OUTPUT"
348+
../bashunit -a contains 'boom from getHash' "$OUTPUT"
349+
../bashunit -a not_contains 'Swallowed by global exception handler' "$OUTPUT"
339350
- script: |
340351
cd e2e/result-cache-restore-without-reflection
341352
composer install

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,8 @@
144144
"patches/Resolver.patch"
145145
],
146146
"symfony/console": [
147-
"patches/OutputFormatter.patch"
147+
"patches/OutputFormatter.patch",
148+
"patches/Application.patch"
148149
]
149150
}
150151
},

composer.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/vendor
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
// Simulates a bootstrap file (e.g. larastan booting Laravel) that installs a
6+
// global exception handler swallowing uncaught exceptions into a clean exit.
7+
// Without PHPStan catching the ResultCacheMetaExtension exception itself, the
8+
// throw from getHash() during result cache restore would escape to this handler
9+
// and the process would silently exit 0 - skipping analysis with green CI.
10+
set_exception_handler(static function (\Throwable $e): void {
11+
fwrite(STDERR, 'Swallowed by global exception handler: ' . $e->getMessage() . "\n");
12+
exit(0);
13+
});
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"autoload-dev": {
3+
"classmap": ["src/"]
4+
}
5+
}

e2e/result-cache-meta-extension-throw/composer.lock

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
parameters:
2+
level: 8
3+
paths:
4+
- src
5+
bootstrapFiles:
6+
- bootstrap.php
7+
8+
services:
9+
-
10+
class: ResultCacheE2E\MetaExtensionThrow\ThrowingResultCacheMetaExtension
11+
tags:
12+
- phpstan.resultCacheMetaExtension
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace ResultCacheE2E\MetaExtensionThrow;
6+
7+
function f(): int
8+
{
9+
return 'definitely not an int';
10+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace ResultCacheE2E\MetaExtensionThrow;
6+
7+
use Error;
8+
use PHPStan\Analyser\ResultCache\ResultCacheMetaExtension;
9+
10+
final class ThrowingResultCacheMetaExtension implements ResultCacheMetaExtension
11+
{
12+
public function getKey(): string
13+
{
14+
return 'e2e-throwing-result-cache-meta-extension';
15+
}
16+
17+
public function getHash(): string
18+
{
19+
throw new Error('boom from getHash');
20+
}
21+
}

0 commit comments

Comments
 (0)