PHPStanを2.0にしただけなのに
PHPStan2.0出ましたね!早速自分も試してみました!
そして早速内部エラー!どうやらRuleErrorTransformerクラスのtransformメソッドが受け取っている引数の型がRuleErrorである必要があるのにstringが渡されている。とのこと。
スタックトレースを見た感じ、どうやらカスタムルールに対するテストが書いてあるファイルを解析している所でエラーが発生している様子。
./vendor/bin/phpstan -vvv analyze
-- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Error
-- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Internal error: PHPStan\Analyser\RuleErrorTransformer::transform(): Argument #1 ($ruleError) must be of type PHPStan\Rules\RuleError, string given, called in
phar:///Users/xyz/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/FileAnalyser.php on line 119 while analysing file
/Users/xyz/tests/CustomRule.php
Post the following stack trace to https://github.com/phpstan/phpstan/issues/new?template=Bug_report.yaml:
## phar:///Users/xyz/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/RuleErrorTransformer.php(19)
#0 phar:///Users/xyz/vendor/phpstan/phpstan/phpstan.phar/src/Analyser/FileAnalyser.php(119):
PHPStan\Analyser\RuleErrorTransformer->transform('Sql::execute()\xE3...', Object(PHPStan\Analyser\MutatingScope), 'PhpParser\\Node\\...', 21)
TL;DR
公式のUPGRADING.mdに書いてありました!ちゃんと読んでなくてすみません!
github.com
カスタムルールで、メッセージを書く部分を以下のようにRuleErrorBuilderを使った書き方に変更することで直ります。
/**
* @implements Rule<StaticCall>
*/
class SqlRule implements Rule
{
public function getNodeType(): string
{
return StaticCall::class;
}
public function processNode(Node $node, Scope $scope): array
{
if (!$node->getArgs()[1]->value instanceof Node\Scalar\String_) {
- return ['第二引数は文字列である必要があります。'];
+ return [RuleErrorBuilder::message('第二引数は文字列である必要があります。')->identifier('error')->build()];
}
(identifierメソッドはあってもなくても良さそうでした)
詳細: processNodeの返り値の型が制限された
変更はこれですね。
実際に確認してみましょう。
2.0未満のPHPStanでは@return (string|RuleError)[] errorsとなっており、string[]が許容されています。
// phpstan-src/src/Rules/Rule.php /** * @phpstan-param TNodeType $node * @return (string|RuleError)[] errors */ public function processNode(Node $node, Scope $scope): array;
一方2.0.xのブランチを確認するとlist<IdentifierRuleError>になっています。そしてこのIdentifierRuleErrorはRuleErrorを継承しています。
/** * @phpstan-param TNodeType $node * @return list<IdentifierRuleError> */ public function processNode(Node $node, Scope $scope): array; // IdentifierRuleErrorはRuleErrorを継承している。 // interface IdentifierRuleError extends RuleError
仮にstring[]の状態でカスタムルールが呼び出されるとFileAnalyser.phpのtranformメソッドにて、RuleError型を必要としている第一引数にstringが渡されることになり、TypeErrorを引き起こす。
という訳です。
// phpstan-src/src/Analyser/FileAnalyser.php line 144 ~ 146 foreach ($ruleErrors as $ruleError) { $temporaryFileErrors[] = $this->ruleErrorTransformer->transform($ruleError, $scope, $nodeType, $node->getStartLine()); }
まとめ
ちゃんと移行用のマニュアル読まなきゃね