PHP PDOStatement 类
最后修改于 2025 年 4 月 19 日
PDOStatement 类代表一个预处理语句及其执行后的结果集。它提供了绑定参数、执行查询和获取结果的方法。
基本定义
PDOStatement 是一个表示预处理语句及其结果的类。它由 PDO::prepare 和 PDO::query 方法返回。
该类提供了用于绑定参数、执行语句、获取结果和检索结果集元数据的方法。
基本查询执行
此示例显示了如何使用 PDOStatement 执行简单查询。
<?php
declare(strict_types=1);
try {
$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->query('SELECT id, name FROM users');
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo "ID: {$row['id']}, Name: {$row['name']}\n";
}
} catch (PDOException $e) {
echo "Error: " . $e->getMessage();
}
这会使用 query 创建一个 PDOStatement 对象。fetch 方法将每一行检索为一个关联数组。循环一直持续到处理完所有行。
带位置参数的预处理语句
这演示了如何使用带问号占位符的预处理语句。
<?php
declare(strict_types=1);
try {
$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->prepare('INSERT INTO products (name, price) VALUES (?, ?)');
$stmt->execute(['Laptop', 999.99]);
echo "Inserted ID: " . $pdo->lastInsertId();
} catch (PDOException $e) {
echo "Error: " . $e->getMessage();
}
prepare 方法创建一个带有占位符的语句模板。execute 按顺序将值绑定到这些占位符。这可以防止 SQL 注入。
预处理语句中的命名参数
这展示了如何使用命名参数来使预处理语句更具可读性。
<?php
declare(strict_types=1);
try {
$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->prepare('UPDATE users SET email = :email WHERE id = :id');
$stmt->execute([
'email' => 'new.email@example.com',
'id' => 42
]);
echo "Affected rows: " . $stmt->rowCount();
} catch (PDOException $e) {
echo "Error: " . $e->getMessage();
}
命名参数以冒号开头,并使用关联数组进行绑定。这使得代码比位置参数更具可读性和可维护性。
显式绑定参数
这演示了使用 bindValue 方法显式绑定参数。
<?php
declare(strict_types=1);
try {
$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->prepare('SELECT * FROM products WHERE price > :min_price AND stock > 0');
$stmt->bindValue(':min_price', 100, PDO::PARAM_INT);
$stmt->execute();
$products = $stmt->fetchAll(PDO::FETCH_OBJ);
foreach ($products as $product) {
echo "Product: {$product->name}, Price: {$product->price}\n";
}
} catch (PDOException $e) {
echo "Error: " . $e->getMessage();
}
bindValue 方法显式地将一个值绑定到一个参数,并指定了数据类型。当您需要将值与执行分开进行绑定时,这很有用。
以不同格式获取数据
这展示了使用 PDOStatement 方法获取数据的各种方式。
<?php
declare(strict_types=1);
try {
$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->query('SELECT id, name, email FROM users LIMIT 5');
// Fetch as associative array
$assoc = $stmt->fetch(PDO::FETCH_ASSOC);
// Fetch all as objects of specific class
$stmt->execute();
$objects = $stmt->fetchAll(PDO::FETCH_CLASS, 'User');
// Fetch into existing object
$user = new User();
$stmt->fetch(PDO::FETCH_INTO, $user);
// Fetch single column
$emails = $stmt->fetchAll(PDO::FETCH_COLUMN, 2);
} catch (PDOException $e) {
echo "Error: " . $e->getMessage();
}
PDOStatement 提供了多种获取样式。FETCH_ASSOC 返回数组,FETCH_CLASS 映射到对象,FETCH_INTO 填充现有对象,FETCH_COLUMN 获取单个列。
PDOStatement 的事务
这演示了如何在数据库事务中使用 PDOStatement。
<?php
declare(strict_types=1);
try {
$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->beginTransaction();
$stmt1 = $pdo->prepare('UPDATE accounts SET balance = balance - ? WHERE id = ?');
$stmt2 = $pdo->prepare('UPDATE accounts SET balance = balance + ? WHERE id = ?');
$stmt1->execute([100, 1]);
$stmt2->execute([100, 2]);
$pdo->commit();
echo "Funds transferred successfully";
} catch (PDOException $e) {
$pdo->rollBack();
echo "Transaction failed: " . $e->getMessage();
}
这展示了在账户之间进行资金转账的原子事务。两个更新都必须成功,否则任何一个都不会被应用。beginTransaction 启动事务,commit 完成事务,rollBack 在失败时取消事务。
处理大型结果集
这演示了如何有效地处理大型结果集。
<?php
declare(strict_types=1);
try {
$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->prepare('SELECT * FROM large_table');
$stmt->execute();
// Process rows one at a time
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
processRow($row);
}
// Alternative method with cursor
$stmt = $pdo->prepare('SELECT * FROM large_table', [
PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL
]);
$stmt->execute();
$stmt->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_ABS, 0); // First row
$stmt->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_REL, 1); // Next row
} catch (PDOException $e) {
echo "Error: " . $e->getMessage();
}
function processRow(array $row): void {
// Process individual row
}
对于大型结果集,一次获取一行而不是使用 fetchAll()。这可以减少内存使用。游标方法允许随机访问行。
最佳实践
- 始终使用预处理语句以防止 SQL 注入
- 显式指定获取模式以获得可预测的结果
- 完成后使用 closeCursor() 关闭游标
- 对多个相关操作使用事务
- 使用 try-catch 块处理错误
来源
本教程涵盖了 PDOStatement 类,并通过实际示例展示了不同场景下的数据库操作。
作者
列出 所有 PHP PDO 函数。