
开发工具代码质量质量保障【免费下载链接】psalmA PHP static analysis tool for finding errors and security vulnerabilities in PHP applications项目地址https://gitcode.com/gh_mirrors/ps/psalm点击查看免费下载Psalm 是 PHP 生态中的静态分析工具能够在不运行代码的前提下发现潜在的错误与安全漏洞。本文聚焦于其内置的TooFewArguments问题类型——当调用函数或方法时传入的实参数量少于被调函数所声明的形参数量Psalm 就会在对应代码位置报告该问题。读完本文你将掌握TooFewArguments的完整触发场景、底层检测算法包括命名参数与数组解包的复杂处理、运行级错误定位方法以及通过 docblock、配置文件和 baseline 三种途径管理该问题的实战方案。问题定义什么是 TooFewArgumentsTooFewArguments在调用函数时若传入的实参数量少于函数声明的形参数量Psalm 即会报告此问题。官方文档给出的最小触发示例为?php function foo(string $a) : void {} foo();在上面的代码中foo声明了一个必填参数$a而调用处foo()没有传入任何参数Psalm 便会在此位置抛出TooFewArguments。与运行期异常的区别这类错误在 PHP 运行期会直接抛出ArgumentCountErrorPHP 8 起或以警告形式中断执行属于确定性的程序缺陷。Psalm 的价值在于静态分析阶段就能在 CI 中拦截它无需等到代码真正执行。这一点在仓库的返回类型提供器 SprintfReturnTypeProvider.php 中体现得尤为直观——该提供器通过构造占位符与实际参数数量不一致的调用捕获ArgumentCountError异常后将其转换为TooFewArguments报告说明 Psalm 自身也把实参不足与运行期ArgumentCountError视为同一类问题的静态等价物。问题类实现错误级别与短码TooFewArguments问题在源码中定义于 TooFewArguments.php?php declare(strict_types1); namespace Psalm\Issue; /** * api */ final class TooFewArguments extends ArgumentIssue { public const ERROR_LEVEL -1; public const SHORTCODE 25; }两个关键常量决定了它的行为特性ERROR_LEVEL -1表示该问题属于始终报错类别。根据 error_levels.md 的说明这类问题误报率极低、代表确定的程序缺陷无法通过调整 error level18来降级或屏蔽。只有psalm-suppress、配置文件issueHandlers或 baseline 才能压制它。在 error_levels.md 的始终视为错误清单中TooFewArguments与UndefinedClass、UndefinedVariable等并列。SHORTCODE 25Psalm 为每个问题分配的唯一短码。在 IssueData.php 中可以看到短码会被格式化为三位数并用于生成指向问题说明页的链接方便在报告输出中快速溯源。此外TooFewArguments继承自 ArgumentIssue.php该抽象基类为所有实参类问题如TooManyArguments、InvalidArgument、NullArgument等增加了function_id属性并在构造时统一将函数名转为小写存储——这保证了同一函数无论以何种大小写形式被调用报告中的标识都能被规范匹配。触发场景详解不只是普通函数调用虽然形参多于实参是最直观的场景但从源码看TooFewArguments在 Psalm 中有多个独立触发点覆盖了用户函数、内置函数、方法调用与特殊语法结构1. 用户自定义函数与方法的实参校验核心检测逻辑位于 ArgumentsAnalyzer.php 的checkArgCount方法。当count($args) count($function_params)时Psalm 会遍历实参将已匹配的形参从待校验列表中剔除然后对剩余形参逐个检查// 剩余未匹配形参中若有必填非可选、非可变参数项则报告 TooFewArguments foreach ($function_params as $i $param) { if (!$param-is_optional !$param-is_variadic) { IssueBuffer::maybeAdd( new TooFewArguments( Too few arguments for . $cased_method_id . - expecting . $param-name . to be passed, $code_location, (string)$method_id, ), $statements_analyzer-getSuppressedIssues(), ); continue; } // ... 对带默认值的参数进行类型推断与模板替换 }这段代码揭示了几条重要规则可选参数带默认值不触发foo(string $a x)即使不传参也合法因为is_optional为真可变参数不触发foo(string ...$args)可以接受零个或多个实参报告信息可定位到具体缺失的参数名例如错误消息Too few arguments for foo - expecting a to be passed会明确指出缺失的是哪个形参这在多参数函数排错时非常有用解包unpack实参参与数量推导当实参是...$arr形式时Psalm 会根据数组类型推导展开后的确定数量——TKeyedArray数组形状按属性数量计、TNonEmptyArray按记录的 count 计、never类型按 0 计只有能确定稳定数量时才继续判定否则放弃检查以避免误报命名参数named arguments按名称匹配命名实参会从形参列表中按名字剔除对应项这意味着以命名方式跳过了某个必填参数同样会触发TooFewArguments。2. 方法调用基于调用结果的结构化报告对于$obj-method(...)形式的方法调用检测发生在 MethodCallAnalyzer.php。方法调用分析器先计算出too_few_arguments标记与方法 ID 列表再统一上报if ($result-too_few_arguments $result-too_few_arguments_method_ids) { $error_method_id $result-too_few_arguments_method_ids[0]; IssueBuffer::maybeAdd( new TooFewArguments( Too few arguments for method . $error_method_id . saw . count($stmt-getArgs()), new CodeLocation($source, $stmt-name), (string) $error_method_id, ), $statements_analyzer-getSuppressedIssues(), ); }注意这里与函数调用报告的不同消息格式为Too few arguments for method ClassName::method saw N同时CodeLocation指向方法名$stmt-name而非整个调用表达式便于精确定位。3. 特殊语法结构clone 与 get_class()clone语句在 CloneAnalyzer.php 中当 clone 语句缺少被克隆的对象实参如 PHP 8 命名参数语法下clone(withProperties: [...])这类写法时会报告Too few arguments for clone - expecting object to be passed。get_class()在 ArgumentsAnalyzer.php 中get_class()无参数调用仅在类作用域内合法在类外调用会报告Cannot call get_class() without argument outside of class scope。4. 内置函数与 CallMap 校验对于 PHP 内置函数Psalm 依赖dictionaries/目录下的 CallMap 文件如 CallMap_84.php声明的参数签名进行校验。测试用例 FunctionCallTest.php 展示了preg_match的检测preg_match(/adsf/); // TooFewArguments - somefile.php:2:21 - Too few arguments for preg_match - expecting subject to be passedpreg_match至少需要两个参数pattern 与 subject这里仅传一个Psalm 依据 CallMap 精确指出缺失的是subject参数。5. 高阶函数array_map 与 array_filter 系列在 ArgumentsAnalyzer.php 中array_map与array_filter系列函数有专门的数量下限校验array_map至少需要 2 个实参回调 数组array_filter系列至少 1 个。测试 ArrayFunctionCallTest.php 验证了这一点function foo(int $i, string $s) : bool { return true; } array_map(foo, [1, 2, 3]); // TooFewArguments回调 foo 需要 2 个参数但只传了 1 个数组实践验证结合测试用例理解判定逻辑仓库测试是理解该问题行为的最佳教材以下用例覆盖了主要分支场景代码预期结果测试位置必填参数缺失function fooFoo(int $a): void {}fooFoo();TooFewArgumentsFunctionCallTest.php内置函数缺失必填参数preg_match(/adsf/);TooFewArguments指出缺失 subjectFunctionCallTest.php命名参数跳过必填项构造函数声明name、problematicOne必填调用仅传name:与id:TooFewArgumentsArgTest.php数组解包缺键构造器需id/name/agenew User(...$data)中$data仅含id/nameTooFewArgumentsArgTest.php高阶函数回调参数不足array_map(foo, [1, 2, 3])foo声明 2 个参数TooFewArgumentsArrayFunctionCallTest.php通过 docblock 压制/** psalm-suppress TooFewArguments */ min(0);不报告FunctionCallTest.php特别值得关注的是命名参数场景ArgTest.phpclass User { public function __construct( protected string $name, protected string $problematicOne, protected string $id , ){} } new User( name: John, id: asd, ); // TooFewArguments必填参数 problematicOne 未被传入这里id有默认值所以合法但必填的problematicOne被跳过了——即使 PHP 运行期会因此抛ArgumentCountErrorPsalm 在静态阶段就已识别出来。问题管理与修复策略由于TooFewArguments属于始终报错级别无法通过调低 error level 屏蔽管理它的手段集中在以下三种1. 从根本上修复补全缺失实参最直接的修复是补齐缺失的参数。对于带默认值的形参若业务上允许缺省则保持不传是合法的Psalm 不会报告若参数确实必填则应补传function foo(string $a) : void {} foo(bar); // 修复传入必填参数2. Docblock 级抑制如果某个调用点确实有意为之例如通过魔术方法或回调签名不匹配的兼容写法可在函数或语句的 docblock 中使用psalm-suppress。根据 dealing_with_code_issues.md支持函数级与行级两种粒度?php /** * psalm-suppress TooFewArguments */ function wrapper() : void { foo(); // 该函数内的调用被抑制 }?php /** * psalm-suppress TooFewArguments */ foo();若需要一次性抑制所有问题可使用psalm-suppress all。3. 配置文件级抑制在psalm.xml中使用issueHandlers标签可按目录、文件粒度抑制详见 dealing_with_code_issues.mdissueHandlers TooFewArguments errorLevel typesuppress directory nametests / /errorLevel /TooFewArguments /issueHandlers也可以仅将级别降为info打印但不中断构建issueHandlers TooFewArguments errorLevelinfo / /issueHandlers4. Baseline 固化存量问题对于存量代码中大量存在、暂时无法一次性修复的TooFewArguments推荐使用 baseline 机制见 dealing_with_code_issues.mdvendor/bin/psalm --set-baseline首次生成 baseline 后存量问题被祖父化不再报错而新增代码中出现同类问题仍会被正常报告实现渐进式修复。与其他实参问题的区分实参数量校验是一个完整的双端体系理解TooFewArguments的同时也应了解它的对称问题TooFewArguments本文实参少于必填形参始终报错TooManyArguments实参多于形参且函数非可变参数。它定义于 TooManyArguments.mdERROR_LEVEL为 1——这意味着在默认 error level 2 下它是报错但在 level 5 及更宽松级别下会被降级为 info见 error_levels.md 的级别对照表。其检测逻辑同样位于 ArgumentsAnalyzer.php报告形如Too many arguments for fooFoo - expecting 1 but saw 2测试见 FunctionCallTest.php。两者在checkArgCount中共享同一套参数匹配框架但TooFewArguments因为ERROR_LEVEL -1而拥有更高的强制级别这反映了设计者的判断漏传参数几乎总是确定性缺陷而多传参数在历史 PHP 版本中更可能存在兼容场景。小结TooFewArguments是 Psalm 实参校验体系中强制级别最高的问题类型覆盖普通函数、方法、内置函数、clone、get_class以及array_map/array_filter系列等全部调用形态。其检测核心 checkArgCount 不仅比较数量还正确处理了默认参数、可变参数、命名参数与数组解包等现代 PHP 语法配套的 FunctionCallTest.php、ArgTest.php 与 ArrayFunctionCallTest.php 提供了覆盖各分支的回归保障。在 CI 流程中遇到该报告时优先按错误消息中expecting X to be passed的提示补全参数确属有意为之再使用抑制或 baseline 手段管理。赞分享开发工具代码质量质量保障【免费下载链接】psalmA PHP static analysis tool for finding errors and security vulnerabilities in PHP applications项目地址https://gitcode.com/gh_mirrors/ps/psalm点击查看免费下载相关推荐Psalm 静态分析LessSpecificImplementedReturnType 问题详解与修复实践Psalm 静态分析LessSpecificImplementedReturnType 问题详解与修复实践 Psalm本仓库即其完整源码在对比类继承 /开发工具代码质量质量保障Psalm 的 InvalidNamedArgument 详解命名参数不匹配问题的检测原理与修复Psalm 的 InvalidNamedArgument 详解命名参数不匹配问题的检测原理与修复 导读 InvalidNamedArgument 是 Psal开发工具代码质量质量保障Psalm InvalidStaticInvocation 详解静态调用实例方法的错误检测与修复Psalm InvalidStaticInvocation 详解静态调用实例方法的错误检测与修复 导读 InvalidStaticInvocation 是 P开发工具代码质量质量保障创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考