PDO 将未在我的类中定义的列拉入我的对象中


PDO pulls in columns into my object that are not defined in my class

所以我定义了一个具有一些预定义属性的类。

class User
{
    public $id;
    public $firstName;
    public $lastName;
}

然后,我使用 PDO::FETCH_CLASS 查询数据库,将结果提取到上述 User 类的对象中。

$sql = "SELECT * FROM users";
$dbh = new PDO($dsn, $username, $password);
$stmt = $dbh->query($sql);
$users = $stmt->fetchAll(PDO::FETCH_CLASS, 'User');
foreach($users as $user)
{
    print_r($user);
}

但是现在,当我迭代生成的User对象时,它包含我在User类中未定义的其他属性。

User Object
(
    [id] => 1
    [firstName] => Bruce
    [lastName] => Wayne
    [city] => Gotham
    [residence] => Batcave
    ...
)

所以。。。

  • 为什么要放入我没有定义的新属性?
  • 如何防止它创建自己的属性?
  • 我做错了什么吗?
  • 即使创建自己的类(模型(并声明属性的目的是什么,如果它只是要把它想要的东西放在那里?
FETCH_CLASS

旨在将结果集的列映射到类中的命名属性。

如果您只需要一些属性,请更改查询并仅获取所需的属性,即

SELECT id, firstName, lastName FROM users

至于解释为什么FETCH_CLASS这样工作,我真的帮不上什么忙。但这就是它的工作原理,你没有做错任何事。如果您希望能够仅使用SELECT * ...并将结果获取到仅填充其定义属性的对象中,我认为PDO没有任何内置部分可以做到这一点。实现此目的的一种方法是为对象创建一个构造函数,该构造函数将使用数组中的值对其进行初始化,如下所示。

class User
{
    public $id;
    public $firstName;
    public $lastName;
    function __construct($record) {
        foreach (get_object_vars($this) as $key => $value) {
            if (isset($record[$key])) $this->$key = $record[$key];
        }
    }
}

然后,您可以改用FETCH_ASSOC,并使用生成的数组创建对象。

while ($record = $stmt->fetch(PDO::FETCH_ASSOC, 'User')) {
    $users[] = new User($record);
}    

我不知道使用这种方法是否会有任何附加值,而不仅仅是指定查询中需要哪些列。您基本上只是将指定可能很长的列列表的工作从查询转移到对象中。

解决此问题的一种方法是在构造函数中检查该类定义了哪些变量:

foreach(get_object_vars($this) as $objVar => $val) {
    $classKeys = array_keys(get_class_vars(self::class));
    foreach(get_object_vars($this) as $objVar => $val) {
        if (!in_array($objVar, $classKeys)) {
            $this->$objVar = null;
        }
    }
}

您最终仍会在类上获得额外的属性,但它们都设置为 null。 我使用了一个 trait 使这个函数在几个类中可用,它运行良好。 然后,您可以使用 setFetchMode 调用上的参数在构造函数中使其成为可选:

$db->setFetchMode(PDO::FETCH_CLASS, 'User', [User::CLEAN]);

然后构造函数可以看起来像这样:

public function __construct($type = null) {
    if ($type == self::CLEAN) {
        $this->clean();
    }
}

这显然不能与PDO::FETCH_PROPS_LATE一起使用。