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

如何使用PDO::FETCH_CLASS将GROUP_CONCAT结果映射为对象数组属性

问题原因说明

PDO::FETCH_CLASS模式的属性赋值规则是:如果目标类中已经声明了对应名称的属性(无论访问修饰符是public、protected还是private),PDO会直接向该属性写入值,不会触发魔术方法__set()。只有当赋值的属性未在类中声明时,才会调用__set(),这就是你之前的方案失效的核心原因。

可行方案(均不需要自行遍历结果集)

方案1:依赖__set()触发逻辑(改动最小)

删除类中提前声明的$referencingNames属性,PDO给不存在的属性赋值时就会自动触发__set(),示例代码如下:

class someObject {
  public int $id;
  public ?array $referencingNames = null;

  public function __set($name, $value) 
  {
    if($name == "referencingNames") {
        $this->referencingNames = explode(",", $value);
        return;
    }
    $this->$name = $value;
  } 
}

原有查询代码不需要修改:

$objects = $statement->fetchAll(PDO::FETCH_CLASS, someObject::class);

方案2:使用PDO::FETCH_FUNC自定义映射(更直观易维护)

这种方式不需要依赖魔术方法的黑盒逻辑,所有转换规则都显式定义,灵活性更高:
目标类保持原有定义即可:

class someObject {
  public int $id;
  public array $referencingNames;
}

查询时传入自定义处理回调:

$objects = $statement->fetchAll(PDO::FETCH_FUNC, function(int $id, string $referencingNames) {
    $obj = new someObject();
    $obj->id = $id;
    $obj->referencingNames = explode(',', $referencingNames);
    return $obj;
});

方案3:使用FETCH_PROPS_LATE配合构造函数

如果你需要保留所有属性的显式声明,可以搭配PDO::FETCH_PROPS_LATE参数使用,该参数会让PDO先调用类的构造函数,再进行属性赋值:

class someObject {
  public int $id;
  public array $referencingNames;
  private string $rawNames;

  public function __construct()
  {
      // 构造函数执行后PDO会完成属性赋值,转换逻辑在__set中实现
  }

  public function __set($name, $value)
  {
      if ($name === 'referencingNames') {
          $this->rawNames = $value;
          $this->referencingNames = explode(',', $value);
          return;
      }
      $this->$name = $value;
  }
}

查询时添加参数:

$objects = $statement->fetchAll(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, someObject::class);

推荐优先使用方案2,逻辑完全透明,后续调整转换规则时不需要修改类定义,适配性更高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.19 18:57:03