PHP Typed属性User::$created_at需DateTime却传入string报错如何解决
根因
你遇到的报错核心原因有两点:
- PHP的
__set()魔术方法仅在给**不可访问属性(不存在、protected或private修饰的属性)**赋值时才会触发,如果你在User类中将$created_at声明为public强类型属性,直接赋值时不会走__set逻辑。 PDO::FETCH_CLASS模式会直接给类的属性赋值,不会触发类的魔术方法,数据库取出的字符串格式时间直接写入要求DateTime类型的属性,就触发了类型错误。
解决方案
方案1:修改属性可见性(改动最小,无需修改Repository代码)
将User类中$created_at属性改为protected/private,同时提供对应的getter方法读取属性,此时PDO赋值时会自动触发__set方法完成时间转换:
// User.php class User { // 改为protected,禁止外部直接访问 protected DateTime $created_at; // 其他属性同理可按需求调整可见性 // 添加getter方法读取时间 public function getCreatedAt(): DateTime { return $this->created_at; } // 你原有__set方法保持不变即可 public function __set($name, $value) { if ($name == 'created_at') $this->$name = new DateTime($value); else $this->$name = $value; } }
方案2:手动映射查询结果(可控性最高,适合复杂属性转换场景)
修改UserRepository的findAll方法,先取出数组格式的查询结果,再手动实例化User对象赋值,确保触发__set逻辑:
// UserRepository.php public function findAll() : array { $stmt = $this->getPDO()->query("SELECT * FROM users"); $users = []; while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { $user = new User(); foreach ($row as $key => $value) { $user->$key = $value; } $users[] = $user; } return $users; }
方案3:使用FETCH_FUNC自定义实例化回调
如果不想写循环遍历,也可以用PDO::FETCH_FUNC模式传入自定义实例化逻辑:
// UserRepository.php public function findAll() : array { return $this->getPDO()->query("SELECT * FROM users")->fetchAll(PDO::FETCH_FUNC, function (array $row) { $user = new User(); foreach ($row as $key => $value) { $user->$key = $value; } return $user; }); }
内容的提问来源于stack exchange,提问作者sisko
相关产品推荐
相关产品推荐

