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

为何PDO::FETCH_CLASS处理小结果集正常,大结果集失效?

问题

我尝试用PDO::FETCH_CLASS把SQL查询结果转换成BibliaTextus类实例,小结果集下代码运行正常,但处理返回83行数据的查询时出错。该查询返回两列,一列是int类型,另一列是text类型。

报错信息

Fatal error: Uncaught TypeError: App\Models\BibliaLectio::add():
 Argument #1 ($bibliaTextus) must be of type App\Models\BibliaTextus,
 array given,  called in
 /MYROUTE/src/App/Domain/Infrastructure/Mapper/Biblia/PdoBibliaMapper.php on line 60  
 and defined in /MYROUTE/src/App/Models/BibliaLectio.php:10

相关代码

PdoBibliaMapper

//..

$bibliaLectio= new \App\Models\BibliaLectio();
$stmt=$this->pdo->run($sql,$params);
$stmt->setFetchMode(PDO::FETCH_CLASS, '\App\Models\BibliaTextus');
while ($row = $stmt->fetch())
{
    $bibliaLectio->add($row); #Line 60
}

BibliaTextus

namespace App\Models;

class BibliaTextus
{

    private int $v;
    private string $t;

    public function toHtml()
    {
        return sprintf('<span class="versiculo">%s</span> %s',$this->v,$this->t);
    }
}

BibliaLectio

namespace App\Models;

class BibliaLectio
{

    private array $list;

    public function add(BibliaTextus $bibliaTextus) #Line 10
    {
        $this->list[]=$bibliaTextus;
    }

    public function toHtml()
    {
        $s='<h1>Texto Bíblico</h1><div class="textus-title"><p>';
        foreach ($this->list as $t)
        {
            $s.=$t->toHtml();
        }
        $s.='</p></div>';
        $s.='<p class="bibliaTextus"><a href="https://example.com/biblia" target="_blank" rel="nofollow">Some Text</p>';
        return $s;
    }
}

原因分析

问题核心是大结果集中存在不符合类属性类型声明的数据:

  • BibliaTextus的$v属性声明为int类型,但结果集中某一行的v列可能是null、空字符串或非数值内容。
  • 当PDO尝试用FETCH_CLASS实例化类时,无法将无效值赋值给强类型的私有属性,此时会 fallback 返回数组而非类实例。
  • 小结果集恰好没有这类无效数据,所以能正常生成类实例;大结果集包含无效数据,就触发了类型错误。

解决方案

1. 排查并修复无效数据

直接查看SQL查询结果,定位到导致错误的行(通常是第83行附近),检查v列的数据是否为有效的整数,修复不符合要求的数据。

2. 调整类属性的类型声明(允许空值)

如果业务逻辑允许v列为空,将BibliaTextus的属性修改为可空类型:

private ?int $v; // 允许int或null
private string $t;

3. 开启PDO异常模式,精准定位错误

在初始化PDO时开启异常错误模式,这样当实例化类失败时会直接抛出异常,方便定位具体问题行:

$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

4. 手动映射数据(更可控)

放弃FETCH_CLASS,手动将数组数据映射到类实例,确保类型转换正确:

// 修改PdoBibliaMapper中的循环部分
while ($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
    // 利用构造函数初始化私有属性
    $textus = new \App\Models\BibliaTextus((int)$row['v'], $row['t']);
    $bibliaLectio->add($textus);
}

对应的,给BibliaTextus添加构造函数:

namespace App\Models;

class BibliaTextus
{
    private int $v;
    private string $t;

    public function __construct(int $v, string $t)
    {
        $this->v = $v;
        $this->t = $t;
    }

    public function toHtml()
    {
        return sprintf('<span class="versiculo">%s</span> %s',$this->v,$this->t);
    }
}

内容的提问来源于stack exchange,提问作者A. Cedano

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 02:36:09