You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让PHPStan识别断言数组键存在的自定义函数

让PHPStan识别自定义的数组键断言函数

PHPStan可以识别直接使用array_key_exists进行数组键存在性检查的代码,示例如下:

<?php declare(strict_types = 1);

/** @return array<mixed> */
function returnMixedArray(): array {
    return [];
}

/**
 * @return array{
 *     existing_key: mixed
 * }
 */
function narrowMixedArrayKeys(): array {
    $foo = returnMixedArray();

    assert(array_key_exists('existing_key', $foo));
    
    return $foo;
}

但当需要批量检查多个数组键的存在性时,我编写了一个通用断言函数,PHPStan却无法理解其类型约束意图:

<?php declare(strict_types = 1);

/**
 * @param array<int|string> $array
 * @param string ...$keys
 */
function assertKeys(array $array, string ...$keys): void {
    foreach ($keys as $key) {
        assert(array_key_exists($key, $array));
    }
}

请问有没有办法让PHPStan识别这个自定义的数组键断言函数?

我明白应该使用对象而非数组,但目前需要维护遗留代码并保障其安全性。


解决方案:利用PHPStan的@phpstan-assert注解与泛型

要让PHPStan理解assertKeys的断言逻辑,需要通过泛型定义和PHPStan专用注解明确函数对数组类型的约束:

1. 修改函数的PHPDoc与实现

更新assertKeys的注解,用泛型绑定键类型,并通过@phpstan-assert告知PHPStan函数执行后的数组类型变化:

<?php declare(strict_types = 1);

/**
 * @template TKey of string
 * @template TValue
 * @param array<TKey|string, TValue> $array
 * @param TKey ...$keys
 * @phpstan-assert array<TKey, TValue> $array
 */
function assertKeys(array $array, string ...$keys): void {
    foreach ($keys as $key) {
        if (!array_key_exists($key, $array)) {
            throw new \InvalidArgumentException("Missing required array key: {$key}");
        }
    }
}

2. 关键细节说明

  • 泛型TKey:约束传入的键与数组键的类型一致性,避免类型不匹配的问题。
  • @phpstan-assert注解:明确告诉PHPStan,执行此函数后,输入的$array必然包含所有传入的$keys,从而完成类型收窄。
  • 替换assert为异常抛出:assert在生产环境可能被禁用,改用抛出InvalidArgumentException既保证运行时安全,也不影响PHPStan的类型推断。

3. 使用示例

调用修改后的assertKeys后,PHPStan会自动识别数组的键存在性:

/** @return array<mixed> */
function getLegacyData(): array {
    return ['id' => 123, 'name' => 'test'];
}

function processLegacyData(): void {
    $data = getLegacyData();
    assertKeys($data, 'id', 'name');
    
    // PHPStan会自动识别$data包含'id'和'name'键,不会报未定义键的错误
    echo $data['id'];
    echo $data['name'];
}

备选方案:自定义PHPStan规则

如果需要处理更复杂的断言逻辑(如混合类型键、嵌套数组),可以编写自定义PHPStan规则,但上述注解方案已经能覆盖绝大多数遗留代码的场景。

内容的提问来源于stack exchange,提问作者Kamil Dzielinski

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 15:18:19