PHP Conference Japan 2024

PDOStatement::fetchObject

(PHP 5 >= 5.1.0, PHP 7, PHP 8, PECL pdo >= 0.2.4)

PDOStatement::fetchObject获取下一行并将其作为对象返回

描述

public PDOStatement::fetchObject(?string $class = "stdClass", array $constructorArgs = []): object|false

获取下一行并将其作为对象返回。此函数是 PDOStatement::fetch() 的替代方案,使用 PDO::FETCH_CLASSPDO::FETCH_OBJ 样式。

获取对象时,其属性将从相应的列值赋值,然后调用其构造函数。

参数

class

创建的类的名称。

constructorArgs

此数组的元素将传递给构造函数。

返回值

返回具有与列名对应的属性名的所需类的实例,或在失败时返回 false

错误/异常

如果属性 PDO::ATTR_ERRMODE 设置为 PDO::ERRMODE_WARNING,则发出级别为 E_WARNING 的错误。

如果属性 PDO::ATTR_ERRMODE 设置为 PDO::ERRMODE_EXCEPTION,则抛出 PDOException

参见

添加笔记

用户贡献笔记 6 个笔记

108
rasmus at mindplay dot dk
11 年前
请注意 PDOStatement::fetchObject() 的相当非正统的行为,它会在调用构造函数之前注入属性值——换句话说,如果你的类在构造函数中将属性值初始化为默认值,你将覆盖 fetchObject() 注入的值!

在你的 __construct() 方法中使用 var_dump($this) 将显示在调用你的构造函数之前属性值已被初始化,所以要小心。

因此,我强烈建议在将数据作为数组检索后手动填充你的对象,而不是尝试让 PDO 直接将属性应用于你的对象。

显然有人认为他们在这里很聪明——允许你从构造函数访问已填充的属性值。不幸的是,这根本不是 OOP 的工作方式——构造函数,根据定义,是构造时调用的第一个方法。

如果你需要在构造和填充对象后初始化对象,我建议你的模型类型实现一个带有 init() 方法的接口,并且你的数据访问层在填充后调用此方法(如果已实现)。
25
Val Bancer
4 年前
如果你希望在 `fetchObject` 设置属性之前调用构造函数,则应使用带有 `PDO::FETCH_PROPS_LATE` 参数的 `PDOStatement::fetch` 方法。
15
beinghavingbreackfast at gmail dot com
9 年前
应该提到,此方法甚至可以设置非公共属性。这听起来很奇怪,但它在根据 mysql 结果创建对象时实际上非常有用。
考虑一个 User 类

<?php
class User {
// 私有属性
private $id, $name;

private function
__construct () {}

public static function
load_by_id ($id) {
$stmt = $pdo->prepare('SELECT id, name FROM users WHERE id=?');
$stmt->execute([$id]);
return
$stmt->fetchObject(__CLASS__);
}
/* 同样的方法可以用“name”列/属性编写 */
}

$user = User::load_by_id(1);
var_dump($user);
?>

fetchObject() 不关心属性是公有的还是私有的。它只是将结果传递给对象。输出类似于

object(User)#3 (2) {
["id":"User":private]=>
string(1) "1"
["name":"User":private]=>
string(10) "John Smith"
}
9
sebastian dot rapetti at alice dot it
7 年前
PDOStatement::fetchObject() 将值注入为字符串,我需要类型转换。

我在类构造函数中包含 settype() 函数来实现它

以下方法按 ID 查找用户并返回用户对象实例

<?php
class UserMapper extends MapperAbstract
{
//其他代码
public function findById(int $userId)
{
$pdos = $this->dBase->prepare('SELECT user_id AS objectId, name, description, password, active, created,
last_update AS lastUpdate FROM user WHERE user_id = :id'
);

$pdos->bindParam(':id', $userId, \PDO::PARAM_INT);
$pdos->execute();

return
$pdos->fetchObject('\DomainObjects\User', array($this->password));
}
//其他代码
}
?>

包含类型处理的User类

<?php
class User extends DomainObjectAbstract
{
//其他代码
public function __construct(Password $password)
{
$this->passwordUtility = $password;

settype($this->objectId, 'integer');
settype($this->active, 'integer');
}
//其他代码
}
?>

返回的User实例的var_dump()

<?php
object
(DomainObjects\User)[18]
public
'name' => string 'root' (length=4)
public
'description' => string 'System User' (length=11)
public
'password' => string '$2y$11$4IAn6SRaB0osPz8afZC5D.CmTrBGxnb5FQEygPjDirK9SWE/u8YuO' (length=60)
public
'active' => int 1
public 'created' => string '2015-02-14 10:39:00' (length=19)
public
'lastUpdate' => string '2016-08-30 18:46:56' (length=19)
private
'passwordUtility' =>
object(Auth\Password)[13]
protected
'options' =>
array (
size=1)
'cost' => int 11
protected 'objectId' => int 1
?>

'objectId' 和 'active' 现在具有所需的类型
3
zlk1214 at gmail dot com
8年前
您可以以面向对象的方式访问MySQL表。假设您有一个名为Users的表,其中包含字段:UserID、UserName、UserPassword、UserBirthday,您可以创建一个扩展DataObject的PHP类,并将其与该表关联。
<?php
class User extends DataObject {
// name: 表名,key: 主键(可以是数组),auto: AUTO_INCREMENT 字段
protected static $_table = array('name' => 'Users', 'key' => 'UserID', 'auto' => 'UserID');
// PHP 属性和 MySQL 字段名之间的关系
protected static $_propertyList = array('id' => 'UserID', 'name' => 'UserName', 'password' => 'UserPassword', 'birthday' => 'UserBirthday');

// 获取所有用户作为数组的方法
public static function GetAll() {
global
$dbh;
$sql = 'SELECT * FROM Users';
$stmt = $dbh->query($sql);
$users = array();
while (
$user = $stmt->fetchObject(__CLASS__)) {
$users[] = $user;
}
return
$users;
}
// 获取特定用户的方法
public static function GetUserByName($name) {}
public static function
GetUserByID($name) {}

// 当前用户对象的方法
public function checkPassword($password) {return $this->password == $password;}
public function
showLink() {return "<a href=\"user.php?i={$this->id}\">{$this->name}</a>";}
}

// 然后,您可以创建此类的实例以在您的表中插入一行
$user = new User();
$user->name = 'oct1158';
$user->password = '789012';
$user->useFunction('birthday', 'NOW()');
echo
'birthday 字段使用 MySQL 函数:', $user->birthday, '<br>';
if (
$user->insert()) {
echo
'新的用户 ID:', $user->id, '<br>';

// 更新行
$user->password = '112233';
$user->update();
} else {
echo
'插入失败<br>';
}
// 通过查询获取特定用户
$sql = 'SELECT * FROM Users WHERE UserName = ?';
$stmt = $dbh->prepare($sql);
$stmt->execute(array('admin'));
$admin_user = $stmt->fetchObject('User');
echo
'管理员 ID 是 ', $admin_user->id, '.<br>';
echo
'管理员生日是 ', $admin_user->birthday, '.<br>';

// 通过类的静态方法获取所有用户
$users = User::GetAll();
echo
'<br>';
echo
$users[0]->name, ', ', $users[0]->birthday, '<br>';
echo
$users[1]->name, ', ', $users[1]->birthday, '<br>';
echo
$users[2]->name, ', ', $users[2]->birthday, '<br>';
echo
'<br>';

// 创建一个空用户,然后立即删除它
$user = new User();
$user->insert();
$user->delete();
?>
DataObject 类示例
<?php
DataObject {
private
$changedFields = array(); // 已更新字段列表
private $data = array(); // 来自 PDOStatement 的原始行
private $funcFields = array(); // 使用 MySQL 函数的字段
// 上述属性在此类中为私有属性,因此即使在您的子类中定义了相同名称的一些属性,或者您将相同名称的属性与表中的字段关联,它们也不会影响这些属性。
function __get($property) {
if (isset(
$this::$_propertyList[$property])) {
return
$this->data[$this::$_propertyList[$property]]; // 通过 PHP 属性访问字段
} else {
return
$this->$property; // 抛出默认的 PHP 错误
}
}
function
__set($property, $value) {
if (isset(
$this::$_propertyList[$property])) {
$field = $this::$_propertyList[$property];
$this->data[$field] = $value; // 更新 $data

// 记录已更改的字段
if (!in_array($field, $this->changedFields)) {
array_push($this->changedFields, $field);
}
$index = array_search($field, $this->funcFields);
if (
$index !== false) {
unset(
$this->funcFields[$index]);
$this->funcFields = array_values($this->funcFields);
}
} else {
// 用于 fetchObject
$this->data[$property] = $value; // 重定向到数组 $data
}
}
private function
checkPrimaryKey() {}
private function
clear() {}
public function
delete() {}
public function
insert() {}
public function
update() {}
public function
useFunction($property, $function) {}
}
?>
2
dave at davidhbrown dot us
9 年前
如果使用命名空间类,则必须提供完全限定的类名;fetchObject 似乎不知道任何“use”语句。

这会导致 PHP 致命错误:找不到类“MyClass”……
<?php
use MyNamespace\MyClass;
// ...
$o = $statement->fetchObject('MyClass'));
?>
这段代码有效
<?php
use MyNamespace\MyClass; // 我的代码仍然需要
// ...
$o = $statement->fetchObject('MyNamespace\\MyClass'));
?>
To Top