PDO中日期字符串转对象报错求助:Undefined变量与foreach参数无效
修复PDO类中日期转换的错误问题
我来帮你拆解一下遇到的这几个错误,然后一步步搞定代码的问题:
错误原因分析
Notice: Undefined variable: dates
你在构造函数里写了foreach($this->$dates AS $date),这里的$dates是一个没有定义的局部变量。你实际要访问的是类的protected $dates属性,应该写成$this->dates(去掉变量名前面的第二个$)。Notice: Undefined property: User::$ 和 Warning: Invalid argument supplied for foreach()
这两个错误都是第一个问题导致的连锁反应:因为$dates未定义,$this->$dates会被PHP解析为访问一个空字符串对应的属性,这个属性肯定不存在,所以foreach拿到的是无效参数,直接报错。隐藏的坑:PDO的
FETCH_CLASS执行顺序
即使你修复了上面的问题,代码还是会出错——因为PDO默认是先调用类的构造函数,再把查询结果的属性赋值给对象。也就是说,你的构造函数执行时,$this->created还没有被赋值,这时候尝试用它创建DateTime对象会抛出新的错误。
修复后的完整代码
<?php ini_set('display_errors', 'On'); // Create a class called user class User { protected $dates = [ 'created', ]; // This is supposed to convert my dates from a string to an object public function __construct() { // 修复:访问类属性$this->dates,而非未定义的局部变量$dates foreach($this->dates AS $date) { // 增加判断,避免属性不存在时出错 if (isset($this->{$date})) { $property = $this->{$date}; $this->{$date} = new DateTime($property); } } } // Adding a public function that will be available outsite of the class public function getFullName() { return "{$this->firstname} {$this->lastname}"; } } $db = new PDO('mysql:host=127.0.0.1;dbname=pdo', 'root', ''); $req = $db->query("SELECT * FROM users"); // 修复:添加PDO::FETCH_PROPS_LATE,让PDO先赋值属性再执行构造函数 $req->setFetchMode(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'User'); ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>PDO</title> </head> <body> <?php while($user = $req->fetch()): ?> <div class="user"> <h4><?php echo $user->getFullName(); ?></h4> <p>Registered on <?php echo $user->created->format('d M Y'); ?></p> <!-- 现在可以正常工作了 --> </div> <?php endwhile; ?> </body> </html>
关键修改说明
- 构造函数的循环变量:把
$this->$dates改为$this->dates,正确访问类的属性。 - PDO获取模式:添加
PDO::FETCH_PROPS_LATE选项,这个选项会让PDO先把查询结果的所有属性赋值给User对象,再调用构造函数,这样构造函数执行时$this->created已经有值了。 - 增加属性存在判断:避免如果数据库中某个日期字段为空或者不存在时,代码抛出新的错误,提升代码健壮性。
现在你再运行代码,应该就能正常把日期字符串转为DateTime对象,并且正确格式化显示了。
内容的提问来源于stack exchange,提问作者James Bissick
相关产品推荐
相关产品推荐

