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

PHPUnit测试中数字字符串传入抽象类int参数未触发TypeError原因求解

PHP8 环境下测试抽象类构造函数参数类型校验异常不触发问题解析

相关代码

抽象类定义

declare(strict_types=1);

abstract class IntValueObject
{
    public function __construct(protected int $value)
    {
    }
}

初始测试用例

declare(strict_types=1);

final class IntValueObjectTest extends TestCase
{
    public function testWithNotValidValue(): void
    {
        $value = '1';
        $this->expectException(\TypeError::class);
        $this->getMockForAbstractClass(IntValueObject::class, [$value]);
    }
}

问题现象

运行上述测试后返回报错:

Api\Tests\Shared\Domain\ValueObject\IntValueObjectTest::testWithNotValidValue
Failed asserting that exception of type "TypeError" is thrown.

另外验证发现两个特殊表现:

  • 将$value的值从'1'改为'foo'后,测试可正常通过
  • 同样传入'1'的场景,PHP8 生产环境会正常抛出TypeError,仅测试环境不触发

问题原因

该问题属于PHP内核已知缺陷:使用PHPUnit的getMockForAbstractClass方法创建抽象类模拟对象时,底层参数处理逻辑会绕过严格类型声明的校验规则,对数值格式的字符串(如'1')会做隐式类型转换为int,不会触发严格模式下的TypeError;只有传入完全无法转为数字的字符串(如'foo')时才会抛出类型异常。

解决方案

不要使用getMockForAbstractClass实例化抽象类进行该场景测试,改用匿名类继承抽象类的方式实现,修改后的测试用例如下:

declare(strict_types=1);

final class IntValueObjectTest extends TestCase
{
    public function testWithNotValidValue(): void
    {
        $value = '1';
        $this->expectException(\TypeError::class);
        new class($value) extends IntValueObject {};
    }
}

匿名类实例化会完全遵循严格类型声明的校验规则,传入'1'时会正常抛出TypeError,测试可正常通过。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.08 12:45:03