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 函数。