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

如何为返回Token数组的PHP Generator添加正确类型提示?

解决Doctrine Lexer Token生成器的类型提示问题

问题背景

我有一个返回Generator的数据提供者,每个生成元素是包含字符串和Token数组的数组,代码如下:

public static function dataProvider(): Generator
{
    yield ['15', [new Token(15, Lexer::T_INTEGER, 0)]];
    // 更多类似项...
}

尝试为该方法添加类型提示:

/** 
 * @return Generator<array{string, Token<int, int|string>[]}>
 */

遇到的PhpStan错误

Generator expects value type 
   array{string, array<Doctrine\Common\Lexer\Token<int, int|string>>}, 
   array{'15',   array{Doctrine\Common\Lexer\Token<int, int>}       } given.

   💡 Offset 1 (array<Doctrine\Common\Lexer\Token<int, int|string>>)
      does not accept type array{Doctrine\Common\Lexer\Token<int, int>}:
      Template type V on class Doctrine\Common\Lexer\Token is not
      covariant.

使用@return Generator<array{string, Token[]}>可消除报错,但会触发“未指定Token的泛型类型T、V”的提示。

Token类定义(来自doctrine/lexer)

/**
 * @template T of UnitEnum|string|int
 * @template V of string|int
 * @implements ArrayAccess<string,mixed>
 */
final class Token implements ArrayAccess

解决方案

问题核心在于Token的模板参数V并非协变类型,无法用更宽泛的int|string去接收更具体的int类型。以下是两种可行的解决方式:

方式一:精确匹配实际泛型类型

如果所有生成的Token实例中,V的类型统一为int,直接将类型提示写精确:

/** 
 * @return Generator<array{string, Token<int, int>[]}>
 */
public static function dataProvider(): Generator
{
    yield ['15', [new Token(15, Lexer::T_INTEGER, 0)]];
    // 更多类似项...
}

方式二:兼容多类型的Token数组

如果数据提供者中同时存在V为int和string的Token,可以用联合类型明确声明数组元素的类型:

/** 
 * @return Generator<array{string, list<Token<int, int>|Token<int, string>>}>
 */
public static function dataProvider(): Generator
{
    yield ['15', [new Token(15, Lexer::T_INTEGER, 0)]];
    yield ['foo', [new Token('foo', Lexer::T_STRING, 0)]];
}

这里用list代替array更贴合实际的索引数组场景,也能让PhpStan做更严格的类型检查。

内容的提问来源于stack exchange,提问作者Alexandre Tranchant

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 07:27:09