Skip to content

Commit c702a5b

Browse files
committed
build(dependencies): Add new PHPStan rules and no-floaters package
- Added "roave/no-floaters" version "^1.13" to enhance code quality checks. - Included "sidz/phpstan-rules" version "^0.5.2" for additional static analysis rules. - These additions aim to improve the overall reliability and maintainability of the codebase.
1 parent 12afa49 commit c702a5b

File tree

11 files changed

+139
-9
lines changed

11 files changed

+139
-9
lines changed

.github/workflows/php-cs-fixer.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,9 @@ jobs:
3737
- name: Run composer install
3838
run: composer install --no-interaction --ansi -v
3939

40+
- name: Run php-cs-fixer with annotate-pull-request format
41+
continue-on-error: true
42+
run: composer php-cs-fixer:fix-dry-run-format-annotate-pull-request
43+
4044
- name: Run php-cs-fixer
4145
run: composer php-cs-fixer:fix-dry-run

.github/workflows/phpstan.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,19 @@ jobs:
3737
- name: Run composer install
3838
run: composer install --no-interaction --ansi -v
3939

40+
# - name: Run phpstan with sarif error format
41+
# continue-on-error: true
42+
# run: composer phpstan:analyse-error-format-sarif
43+
#
44+
# - name: Upload the analysis results of sarif to GitHub
45+
# uses: github/codeql-action/upload-sarif@v4
46+
# with:
47+
# sarif_file: .build/phpstan/results.sarif
48+
# wait-for-processing: true
49+
50+
- name: Run phpstan with annotate-pull-request error format
51+
continue-on-error: true
52+
run: composer phpstan:analyse-error-format-annotate-pull-request
53+
4054
- name: Run phpstan
4155
run: composer phpstan:analyse

.github/workflows/rector.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,9 @@ jobs:
3737
- name: Run composer install
3838
run: composer install --no-interaction --ansi -v
3939

40+
- name: Run rector with github output format
41+
continue-on-error: true
42+
run: composer rector:process-dry-run-output-format-github
43+
4044
- name: Run rector
4145
run: composer rector:process-dry-run

baselines/loader.neon

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
# total 4 errors
1+
# total 1 error
22

33
includes:
4+
- shipmonk.checkedExceptionInCallable.neon
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# total 1 error
2+
3+
parameters:
4+
ignoreErrors:
5+
-
6+
message: '#^Throwing checked exception ErrorException in closure\!$#'
7+
count: 1
8+
path: ../src/Support/helpers.php

composer.json

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,10 @@
4646
"ergebnis/composer-normalize": "^2.48",
4747
"ergebnis/license": "^2.7",
4848
"ergebnis/php-cs-fixer-config": "^6.58",
49+
"ergebnis/phpstan-rules": "^2.12",
4950
"ergebnis/rector-rules": "^1.9",
5051
"fakerphp/faker": "^1.24",
51-
"guanguans/php-cs-fixer-custom-fixers": "^1.0",
52+
"guanguans/php-cs-fixer-custom-fixers": "^1.1",
5253
"guanguans/rector-rules": "^1.3",
5354
"mockery/mockery": "^1.6",
5455
"nette/utils": "^3.2 || ^4.0",
@@ -70,9 +71,12 @@
7071
"shipmonk/dead-code-detector": "^0.14",
7172
"shipmonk/name-collision-detector": "^2.1",
7273
"shipmonk/phpstan-baseline-per-identifier": "^2.3",
74+
"shipmonk/phpstan-rules": "^4.3",
7375
"spatie/pest-plugin-snapshots": "^1.1 || ^2.0",
7476
"spaze/phpstan-disallowed-calls": "^4.7",
77+
"staabm/annotate-pull-request-from-checkstyle": "^1.8",
7578
"staabm/phpstan-todo-by": "^0.3",
79+
"staabm/side-effects-detector": "^1.0",
7680
"symfony/thanks": "^1.3",
7781
"symfony/var-dumper": "^5.4 || ^6.0 || ^7.0 || ^8.0",
7882
"symplify/phpstan-rules": "^14.9",
@@ -195,7 +199,7 @@
195199
"@pest"
196200
],
197201
"class-leak": "@php vendor/bin/class-leak --ansi -vv",
198-
"class-leak:check": "@class-leak check src/ --skip-type=Guanguans\\PHPStanRules\\Contract\\ThrowableContract --skip-path=Support/",
202+
"class-leak:check": "@class-leak check src/ --skip-type=Guanguans\\PHPStanRules\\Contract\\ThrowableContract --skip-type=Guanguans\\PHPStanRules\\Rule\\ExceptionRule --skip-path=Support/",
199203
"composer-bump": [
200204
"@putenv:php",
201205
"@composer-config:disable-process-timeout",
@@ -315,6 +319,7 @@
315319
],
316320
"php-cs-fixer:fix": "@php-cs-fixer fix --show-progress=dots --diff",
317321
"php-cs-fixer:fix-dry-run": "@php-cs-fixer:fix --dry-run",
322+
"php-cs-fixer:fix-dry-run-format-annotate-pull-request": "@php vendor/bin/php-cs-fixer --ansi -vv 'fix' '--show-progress=dots' '--diff' '--dry-run' --format=checkstyle | vendor/bin/cs2pr --notices-as-warnings --colorize",
318323
"php-cs-fixer:list-files": "@php-cs-fixer list-files",
319324
"php-cs-fixer:list-sets": "@php-cs-fixer list-sets --ansi -vv",
320325
"php-lint": [
@@ -335,6 +340,12 @@
335340
],
336341
"phpstan-rules:list-files": "Guanguans\\PHPStanRules\\Support\\ComposerScripts::listFiles",
337342
"phpstan:analyse": "@phpstan analyse",
343+
"phpstan:analyse-error-format-annotate-pull-request": "@php vendor/bin/phpstan --ansi -vv 'analyse' --error-format=checkstyle | vendor/bin/cs2pr --notices-as-warnings --colorize",
344+
"phpstan:analyse-error-format-github": "@phpstan:analyse --error-format=github",
345+
"phpstan:analyse-error-format-sarif": [
346+
"[ -d .build/phpstan/ ] || mkdir -p .build/phpstan/",
347+
"@php vendor/bin/phpstan --ansi -vv 'analyse' --error-format=sarif > .build/phpstan/results.sarif"
348+
],
338349
"phpstan:analyse-generate-baseline": "@phpstan:analyse --generate-baseline --allow-empty-baseline",
339350
"phpstan:analyse-split-baseline": [
340351
"@phpstan:analyse --generate-baseline=baselines/loader.neon --allow-empty-baseline",
@@ -348,6 +359,10 @@
348359
"@php vendor/bin/pint --ansi -vv"
349360
],
350361
"pint:test": "@pint --test",
362+
"pint:test-format-annotate-pull-request": [
363+
"@putenv:xdebug-off",
364+
"@php vendor/bin/pint --ansi -vv '--test' --format=checkstyle | vendor/bin/cs2pr --notices-as-warnings --colorize"
365+
],
351366
"putenv:composer-memory-unlimited": "@putenv COMPOSER_MEMORY_LIMIT=-1",
352367
"putenv:php": [
353368
"@putenv PHP74=/opt/homebrew/opt/php@7.4/bin/php",
@@ -370,8 +385,14 @@
370385
"rector:process-clear-cache": "@rector:process --clear-cache",
371386
"rector:process-clear-cache-dry-run": "@rector:process-clear-cache --dry-run",
372387
"rector:process-dry-run": "@rector:process --dry-run",
388+
"rector:process-dry-run-output-format-github": "@rector:process-dry-run --output-format=github",
373389
"rector:process-only": "@rector:process-clear-cache tests.php --only=Guanguans\\PHPStanRules\\Rector\\Array_\\SortListItemOfSameScalarTypeRector",
374390
"rector:process-only-dry-run": "@rector:process-only --dry-run",
391+
"roave-backward-compatibility-check": [
392+
"@putenv:php",
393+
"$PHP82 vendor/bin/roave-backward-compatibility-check --ansi -vv"
394+
],
395+
"roave-backward-compatibility-check:format-github-actions": "@roave-backward-compatibility-check --format=github-actions",
375396
"rule-doc-generator": [
376397
"@putenv:php",
377398
"$PHP82 rule-doc-generator --ansi -vv"

phpstan.neon.dist

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ parameters:
5353
allRules: true
5454
booleansInConditions: false
5555
disallowedShortTernary: false
56+
ergebnis:
57+
noParameterWithNullableTypeDeclaration:
58+
enabled: false
59+
noParameterWithNullDefaultValue:
60+
enabled: false
5661
cognitive_complexity:
5762
class: 42
5863
function: 8
@@ -130,7 +135,7 @@ parameters:
130135
- identifier: return.type
131136
- identifier: symplify.explicitInterfaceSuffixName
132137
# - identifier: symplify.forbiddenArrayMethodCall
133-
# - identifier: symplify.forbiddenNode
138+
- identifier: symplify.forbiddenNode
134139
# - identifier: symplify.forbiddenStaticClassConstFetch
135140
# - identifier: symplify.noArrayMapWithArrayCallable
136141
# - message: '#^Unused Guanguans\\PHPStanRules\\Rector\\.*\\.*\:\:__construct$#'
@@ -144,6 +149,9 @@ parameters:
144149
-
145150
identifier: symplify.forbiddenFuncCall
146151
path: src/Support/helpers.php
152+
-
153+
identifier: shipmonk.unusedParameter
154+
path: src/Support/helpers.php
147155

148156
- identifier: typeCoverage.paramTypeCoverage
149157
# - identifier: typeCoverage.returnTypeCoverage

rector.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ classes(static fn (string $class, string $file): bool => str_starts_with($class,
200200
])
201201
->withSkip([
202202
NewExceptionToNewAnonymousExtendsExceptionImplementsRector::class => [
203+
__DIR__.'/src/Support/helpers.php',
203204
__DIR__.'/tests/Support/HelpersTest.php',
204205
],
205206
SortAssociativeArrayByKeyRector::class => [

src/Rule/ExceptionRule.php

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+
/**
6+
* Copyright (c) 2026 guanguans<ityaozm@gmail.com>
7+
*
8+
* For the full copyright and license information, please view
9+
* the LICENSE file that was distributed with this source code.
10+
*
11+
* @see https://github.com/guanguans/phpstan-rules
12+
*/
13+
14+
namespace Guanguans\PHPStanRules\Rule;
15+
16+
/**
17+
* @see \Guanguans\RectorRules\Rector\New_\NewExceptionToNewAnonymousExtendsExceptionImplementsRector
18+
* @see https://github.com/symfony/ai/blob/main/.phpstan/ForbidNativeExceptionRule.php
19+
* @see https://github.com/thecodingmachine/phpstan-strict-rules/tree/master/src/Rules/Exceptions/
20+
*/
21+
final class ExceptionRule {}

src/Support/helpers.php

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@
2929
* @see \get_declared_classes()
3030
* @see \get_declared_interfaces()
3131
* @see \get_declared_traits()
32-
* @see \DG\BypassFinals::enable()
3332
* @see \Composer\Util\ErrorHandler
33+
* @see \Composer\Util\Silencer::call()
34+
* @see \DG\BypassFinals::enable()
35+
* @see \Illuminate\Foundation\Bootstrap\HandleExceptions::bootstrap()
3436
* @see \Monolog\ErrorHandler
3537
* @see \PhpCsFixer\ExecutorWithoutErrorHandler
3638
* @see \Phrity\Util\ErrorHandler
@@ -41,6 +43,8 @@
4143
*
4244
* @param null|(callable(class-string<TObject>, string): bool) $filter
4345
*
46+
* @throws \ErrorException
47+
*
4448
* @return \Illuminate\Support\Collection<class-string<TObject>, \ReflectionClass<TObject>|\Throwable>
4549
*
4650
* @noinspection PhpUndefinedNamespaceInspection
@@ -49,21 +53,59 @@ function classes(?callable $filter = null): Collection
4953
{
5054
$filter ??= static fn (string $class, string $file): bool => true;
5155

52-
/** @var null|\Illuminate\Support\Collection $classes */
56+
/** @var null|\Illuminate\Support\Collection<string, class-string> $classes */
5357
static $classes;
5458
$classes ??= collect(spl_autoload_functions())->flatMap(
5559
static fn (callable $loader): array => \is_array($loader) && $loader[0] instanceof ClassLoader
5660
? $loader[0]->getClassMap()
5761
: []
5862
);
5963

64+
/** @var null|array{class: class-string<TObject>, line: int} $context */
65+
static $context = null;
66+
static $registered = false;
67+
68+
if (!$registered) {
69+
register_shutdown_function(
70+
static function (string $func) use (&$context): void {
71+
// @codeCoverageIgnoreStart
72+
if (
73+
null === $context
74+
|| null === ($error = error_get_last())
75+
|| !\in_array($error['type'], [\E_COMPILE_ERROR, \E_CORE_ERROR, \E_ERROR, \E_PARSE], true)
76+
) {
77+
return;
78+
}
79+
80+
// trigger_error('Error message...', \E_USER_ERROR);
81+
throw new \ErrorException(
82+
"Fatal Error detected during reflection of class [{$context['class']}]".\PHP_EOL.
83+
"You may need to filter out the class using the callback parameter of the function [$func()]",
84+
0,
85+
$error['type'],
86+
__FILE__,
87+
$context['line'],
88+
new \ErrorException($error['message'], 0, $error['type'], $error['file'], $error['line'])
89+
);
90+
// @codeCoverageIgnoreEnd
91+
},
92+
__FUNCTION__
93+
);
94+
95+
$registered = true;
96+
}
97+
6098
return $classes
6199
->filter(static fn (string $file, string $class): bool => $filter($class, $file))
62-
->mapWithKeys(static function (string $file, string $class): array {
100+
->mapWithKeys(static function (string $file, string $class) use (&$context): array {
63101
try {
102+
$context = ['class' => $class, 'line' => __LINE__ + 2];
103+
64104
return [$class => new \ReflectionClass($class)];
65105
} catch (\Throwable $throwable) {
66106
return [$class => $throwable];
107+
} finally {
108+
$context = null;
67109
}
68110
});
69111
}

0 commit comments

Comments
 (0)