如何在PHPStan中判断方法参数是否为字面量/标量字符串(含拼接)
解决方案
要实现只允许纯字符串字面量拼接的参数校验,核心是递归检查拼接表达式的每一部分,确保所有参与拼接的都是标量字符串,不包含变量、常量、函数调用等非标量内容。
修改后的完整代码如下:
<?php final class StringArgumentOnlyRule implements Rule { public function getNodeType(): string { return MethodCall::class; } public function processNode(Node $node, Scope $scope): array { $allArgs = $node->getArgs(); $firstArg = reset($allArgs); // 检查第一个参数是否为纯字符串字面量或其合法拼接 if ($this->isPureStringConcat($firstArg->value)) { return []; } return ['Must be a string (only scalar literals or their concatenation allowed).']; } /** * 递归验证表达式是否为纯字符串字面量或合法的字符串拼接 */ private function isPureStringConcat(Node $expr): bool { // 情况1:本身就是标量字符串 if ($expr instanceof Scalar_String) { return true; } // 情况2:是字符串拼接操作,递归检查左右两边 if ($expr instanceof Expr_BinaryOp_Concat) { return $this->isPureStringConcat($expr->left) && $this->isPureStringConcat($expr->right); } // 其他情况(变量、常量、函数调用等)都不合法 return false; } }
关键逻辑说明
- 递归校验函数:
isPureStringConcat会逐层拆解拼接表达式:- 如果当前节点是
Scalar_String(纯字符串字面量),直接返回合法; - 如果是
Expr_BinaryOp_Concat(字符串拼接操作),则递归检查左右两个子表达式是否都合法; - 任何其他类型的节点(比如
Expr_Variable变量、Expr_ConstFetch常量、Expr_FuncCall函数调用)都会返回不合法。
- 如果当前节点是
- 主逻辑修改:原来的代码只判断单个标量字符串,现在替换为调用递归函数,覆盖了多段字符串拼接的场景。
这样就能满足需求:允许'a' . 'b' . 'c'这类纯字面量拼接,但拒绝'a' . $var、sprintf('a')、CONSTANT . 'b'等包含非标量内容的情况。
内容的提问来源于stack exchange,提问作者TravisCarden
相关产品推荐
相关产品推荐

