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

如何在PHP/PHPStan中返回带泛型提示的通用接口?

PHP/PHPStan泛型类型提示:返回带泛型的接口对象并限制方法调用

需求明确:

  • 调用创建函数后,返回的接口对象的build()方法必须返回具体的Car类型
  • 不能调用实现类(如CarBuilder)特有的notAnInterfaceFunc()方法

现有代码示例:

class Car
{
}

/**
 * @template S of object
 */
interface BuilderInterface
{
    /**
     * @return S
     */
    public function build(): object;
}

/**
 * @implements BuilderInterface<Car>
 */
class CarBuilder implements BuilderInterface
{
    public function build(): object
    {
        return new Car();
    }
    
    public function notAnInterfaceFunc(): void
    {
    }
}

/**
 * @template T of BuilderInterface
 * @param class-string<T> $builderClass
 * @return T
 */
function createBuilder(string $builderClass): BuilderInterface
{   
    return new $builderClass();
}

/**
 * @template T of BuilderInterface
 * @param class-string<T> $builderClass
 * @return BuilderInterface
 */
function createBuilder1(string $builderClass): BuilderInterface
{   
    return new $builderClass();
}

// 现有问题:
$builder = createBuilder(CarBuilder::class);
\PHPStan\dumpType($builder->build()); // 正确返回Car,但能调用notAnInterfaceFunc()
$builder->notAnInterfaceFunc(); // 无报错,不符合需求

$builder1 = createBuilder1(CarBuilder::class);
\PHPStan\dumpType($builder1->build()); // 仅返回object,类型丢失,不符合需求

问题分析

  • createBuilder:返回泛型参数T(即实现类本身),因此能调用实现类的所有方法,但不符合“仅暴露接口方法”的要求
  • createBuilder1:返回无泛型的BuilderInterface,泛型类型信息丢失,导致build()无法推断出具体的Car类型

解决方案

调整函数的泛型定义,同时约束实现类的泛型参数,让函数返回带有具体泛型参数的BuilderInterface:

/**
 * @template S of object
 * @param class-string<BuilderInterface<S>> $builderClass
 * @return BuilderInterface<S>
 */
function createBuilderCorrect(string $builderClass): BuilderInterface
{   
    return new $builderClass();
}

修改后验证

$builderCorrect = createBuilderCorrect(CarBuilder::class);
\PHPStan\dumpType($builderCorrect->build()); // 输出:Car(正确)
$builderCorrect->notAnInterfaceFunc(); // PHPStan报错:Method notAnInterfaceFunc() does not exist on BuilderInterface<Car>(符合需求)

完整修改后代码

class Car
{
}

/**
 * @template S of object
 */
interface BuilderInterface
{
    /**
     * @return S
     */
    public function build(): object;
}

/**
 * @implements BuilderInterface<Car>
 */
class CarBuilder implements BuilderInterface
{
    public function build(): object
    {
        return new Car();
    }
    
    public function notAnInterfaceFunc(): void
    {
    }
}

/**
 * @template S of object
 * @param class-string<BuilderInterface<S>> $builderClass
 * @return BuilderInterface<S>
 */
function createBuilderCorrect(string $builderClass): BuilderInterface
{   
    return new $builderClass();
}

// 验证效果
$builderCorrect = createBuilderCorrect(CarBuilder::class);
\PHPStan\dumpType($builderCorrect->build());
// $builderCorrect->notAnInterfaceFunc(); // 取消注释会触发PHPStan错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 15:53:10