点击蓝字关注我们!每天获取最新的编程小知识!
源 / php中文网 源 / www.php.cn
与任何其他数据库扩展一样,PDO可以直接从所选数据创建现有类的实例。但是,与其他扩展不同的是,PDO为强大而灵活的对象操作提供了许多特性。
(查看原文请点击本文末尾左下角:
获取单个对象
要从查询结果创建单个对象,有两种方法。
1.使用熟悉的fetch()方法:
class
User {};
$stmt
=
$pdo
->query(
'SELECT name FROM users LIMIT 1'
);
$stmt
->setFetchMode(PDO::FETCH_CLASS,
'User'
);
$user
=
$stmt
->fetch();
class
User {};
$user
=
$pdo
->query(
'SELECT name FROM users LIMIT 1'
)->fetchObject(
'User'
);
虽然这两个代码段都将为你提供相同的User类实例,
/* object(User)#3 (1) {
["name"] => string(4) "John"
} */
后一种方法看起来绝对更简洁。此外,如果使用了fetch()方法,但是没有使用这样的名称定义类,则将静默返回一个数组,而使用fetchObject()将抛出一个适当的错误。
获取对象数组
当然,上面描述的两种方法都可以与一个熟悉的while语句一起使用,从数据库中获取结果行。
使用一个方便的fetchAll()方法一次获取对象数组中所有返回的记录:
class
User {};
$users
=
$pdo
->query(
'SELECT name FROM users'
)->fetchAll(PDO::FETCH_CLASS,
'User'
);
/* array(2) {
[0]=> object(User)#3 (1) {
["name"] => string(4) "John"
}
[1]=> object(User)#4 (1) {
["name"]=> string(4) "Mike"
}
} */
注意,
你可以将此模式与PDO::FETCH_UNIQUE和PDO::FETCH_GROUP组合使用,以获得由唯一字段索引的结果数组,或者分别使用非唯一字段对结果进行分组。
例如,下面的代码将返回一个数组,其中记录id将用作数组索引而不是连续数字。
class
User {};
$stmt
=
$pdo
->query(
'SELECT id, id, name, car FROM users'
);
$users
= ->fetchAll(PDO::FETCH_CLASS|PDO::FETCH_UNIQUE,
'User'
);
分配类属性
无论选择哪种方法,查询返回的所有列都将按照以下规则分配给对应的类属性:
1.如果有一个类属性,它的名称与列名相同,则将为该属性分配列值
2.如果没有这样的属性,那么将调用一个魔术方法__set()
3.如果没有为该类定义__set()方法,那么将创建一个公共属性并为其分配一个列值。
例如,这段代码
class
User
{
public
$name
;
}
$user
=
$pdo
->query(
'SELECT * FROM users LIMIT 1'
)->fetchObject(
'User'
);
/* object(User)#3 (4) {
["id"] => string(3) "104"
["name"] => string(4) "John"
["sex"] => string(4) "male"
["car"] => string(6) "Toyota"
} */
从这一点可以看出,为了避免自动创建属性,你可以使用魔术方法__set()过滤掉属性。最简单的过滤技术就是一个空的__set()方法。使用它,只会设置现有的属性:
class
User
{
private
$name
;
public
function
__set(
$name
,
$value
) {}
}
$user
=
$pdo
->query(
'SELECT * FROM users LIMIT 1'
)->fetchObject(
'User'
);
/*
array(1) {
[0]=> object(User)#3 (1) {
["name":"User":private]=> string(4) "John"
}
} */
如上PDO还可以为私有属性分配值。
将构造函数参数传递给对象
当然,对于新创建的对象,我们可能需要提供构造函数参数。为此,fetchObject()和fetchAll()方法都有一个专用的参数,你可以使用它以数组的形式传递构造函数参数。
假设我们有一个类User,它有一个car属性,可以通过提供的变量在构造函数中设置:
class
User {
public
function
__construct(
$car
) {
$this
->car =
$car
;
}
}
$users
=
$pdo
->query(
'SELECT name FROM users LIMIT 1'
)
->fetchAll(PDO::FETCH_CLASS,
'User'
, [
'Caterpillar'
]);
$user
=
$pdo
->query(
'SELECT name FROM users LIMIT 1'
)
->fetchObject(
'User'
,[
'Caterpillar'
]);
/* object(User)#3 (2) {
["name"] => string(4) "John"
["car"] => string(11) "Caterpillar"
} */
可以看到,数据库中的值被覆盖了,因为默认情况下PDO在调用构造函数之前分配类属性。这可能是一个问题,但很容易解决:
在调用构造函数后设置类属性
mysql_fetch_object()注释:
如果你使用mysql_fetch_object并指定一个类——属性将在构造函数执行之前设置。这通常不是问题,但是如果你的属性是通过__set()魔术方法设置的,那必须首先执行构造函数逻辑,否则可能会导致一些主要问题。
可惜mysql是一个mysqli扩展,但我们使用的是PDO。因此,有一种方法可以告诉PDO在构造函数执行之后分配属性。为此,必须使用PDO::FETCH_PROPS_LATE常量。
使用fetchAll()将非常简单,
class
User {
public
function
__construct(
$car
) {
$this
->car =
$car
;
}
}
$stmt
=
$pdo
->query(
'SELECT name, car FROM users LIMIT 1'
);
$users
=
$stmt
->fetchAll(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE,
'User'
, [
'Caterpillar'
]);
class
User {
public
function
__construct(
$car
) {
$this
->car =
$car
;
}
}
$stmt
=
$pdo
->query(
'SELECT name, car FROM users LIMIT 1'
);
$stmt
->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE,
'User'
);
$user
=
$stmt
->fetchObject(
'User'
, [
'Caterpillar'
]);
/*
object(User)#3 (2) {
["car"] => string(6) "Toyota"
["name"] => string(4) "John"
} */
如上这段代码效率并不高,因为我们必须编写两次类名。
或者,我们可以使用fetch():
$stmt
=
$pdo
->query(
'SELECT name, car FROM users LIMIT 1'
);
$stmt
->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE,
'User'
, [
'Caterpillar'
]);
$user
=
$stmt
->fetch();
但是,如上所述,如果一个类恰好是未定义的,它将无法帮助我们处理错误消息。
从数据库中获取类名
还有一个更有趣的标志,它告诉PDO从第一列的值中获取类名。使用这个标志,可以避免使用setFetchMode()和fetch():
$data
=
$pdo
->query(
"SELECT 'User', name FROM users"
)
->fetch(PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE);
/*
object(User)#3 (1) {
["name"]=> string(4) "John"
} */
class
Male {};
class
Female {};
$stmt
=
$pdo
->query(
'SELECT sex, name FROM users'
);
$users
=
$stmt
->fetchAll(PDO::FETCH_CLASS | PDO::FETCH_CLASSTYPE);
/*
array(6) {
[0]=> object(Male)#3 (1) {
["name"]=> string(4) "John"
}
[1]=> object(Male)#4 (1) {
["name"]=> string(4) "Mike"
}
[2]=> object(Female)#5 (1) {
["name"]=> string(4) "Mary"
}
[3]=> object(Female)#6 (1) {
["name"]=> string(5) "Kathy"
}
}*/
然而,当使用这种模式时,似乎不可能在类构造函数中传递任何参数。
更新现有对象
除了创建新对象,PDO还可以更新现有对象。只使用setFetchMode(),它将现有变量作为参数。显然,使用fetchAll()是无用的。
class
User
{
public
$name
;
public
$state
;
public
function
__construct()
{
$this
->name = NULL;
}
}
$user
=
new
User;
$user
->state =
"up'n'running"
;
var_dump(
$user
);
$stmt
=
$pdo
->query(
'SELECT name FROM users LIMIT 1'
);
$stmt
->setFetchMode(PDO::FETCH_INTO,
$user
);
$data
=
$stmt
->fetch();
var_dump(
$data
,
$user
);
/*
object(Foo)#2 (2) {
["name"] => NULL
["state"] => string(12) "up'n'running"
}
object(Foo)#2 (2) {
["name"] => string(4) "John"
["state"] => string(12) "up'n'running"
}
object(Foo)#2 (2) {
["name"] => string(4) "John"
["state"] => string(12) "up'n'running"
} */
-END-
声明:本文选自「 php中文网 」,搜索「 phpcnnew 」即可关注!
▼