PHP PDO::prepare 方法
最后修改于 2025 年 4 月 19 日
PDO::prepare 方法是 PHP PDO 扩展的关键部分。它为执行准备 SQL 语句并返回一个语句对象。本教程将通过实际示例深入讲解 PDO::prepare。
基本定义
PDO::prepare 为执行准备 SQL 语句。它返回一个 PDOStatement 对象。SQL 可以包含零个或多个参数标记。
语法:public PDO::prepare(string $statement, array $driver_options = array()): PDOStatement|false
。语句可以包含命名 (:name) 或问号 (?) 参数。
基本预处理语句示例
这展示了 PDO::prepare 与位置参数的最简单用法。
<?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 users (name, email) VALUES (?, ?)"); $stmt->execute(['John Doe', 'john@example.com']); echo "Record inserted successfully"; } catch (PDOException $e) { echo "Error: " . $e->getMessage(); }
此示例使用两个位置参数准备了一个 INSERT 语句。execute 方法将值绑定到这些参数。这通过将数据与 SQL 命令分离来防止 SQL 注入。
命名参数示例
命名参数使 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("SELECT * FROM users WHERE email = :email"); $stmt->execute(['email' => 'john@example.com']); $user = $stmt->fetch(); if ($user) { echo "Found user: {$user['name']}"; } } catch (PDOException $e) { echo "Error: " . $e->getMessage(); }
这在 SQL 语句中使用了一个名为 :email 的参数。execute 方法接受一个关联数组,其中键与参数名称匹配。命名参数在 SQL 中以冒号作为前缀。
显式绑定参数
bindParam 和 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("INSERT INTO products (name, price) VALUES (:name, :price)"); $name = "Laptop"; $price = 999.99; $stmt->bindParam(':name', $name, PDO::PARAM_STR); $stmt->bindParam(':price', $price, PDO::PARAM_STR); $stmt->execute(); echo "Product added successfully"; } catch (PDOException $e) { echo "Error: " . $e->getMessage(); }
这演示了使用 bindParam 进行的显式参数绑定。第三个参数指定数据类型。bindParam 通过引用绑定,而 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("INSERT INTO orders (product_id, quantity) VALUES (?, ?)"); // First execution $stmt->execute([1, 2]); // Second execution $stmt->execute([3, 1]); // Third execution $stmt->execute([5, 3]); echo "Multiple orders inserted successfully"; } catch (PDOException $e) { echo "Error: " . $e->getMessage(); }
这显示了预处理语句在批量操作中的效率。SQL 只解析和编译一次。每次执行都使用新的参数值。这种模式非常适合插入多个相似的记录。
使用预处理语句获取数据
预处理语句与 SELECT 查询一起用于安全的数据检索。
<?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 id, name, email FROM users WHERE active = :active"); $stmt->execute(['active' => 1]); $users = $stmt->fetchAll(PDO::FETCH_ASSOC); foreach ($users as $user) { echo "ID: {$user['id']}, Name: {$user['name']}\n"; } } catch (PDOException $e) { echo "Error: " . $e->getMessage(); }
这使用预处理语句获取活动用户。fetchAll 一次性检索所有结果,作为关联数组。:active 参数确保将值安全地插入到查询中。始终以这种方式过滤用户输入。
带有 LIKE 子句的预处理语句
LIKE 子句中的特殊字符需要仔细处理 PDO。
<?php declare(strict_types=1); try { $pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password'); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $search = "%smith%"; $stmt = $pdo->prepare("SELECT * FROM users WHERE lastname LIKE ?"); $stmt->execute([$search]); $results = $stmt->fetchAll(); foreach ($results as $row) { echo "Found: {$row['firstname']} {$row['lastname']}\n"; } } catch (PDOException $e) { echo "Error: " . $e->getMessage(); }
这会搜索包含“smith”的名称。百分号是绑定参数的一部分,而不是 SQL 的一部分。这可以防止 SQL 注入,同时允许通配符搜索。始终将通配符添加到参数值中。
带预处理语句的事务
预处理语句与 PDO 事务无缝配合,以确保数据完整性。
<?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 = ?"); $amount = 100; $from = 1; $to = 2; $stmt1->execute([$amount, $from]); $stmt2->execute([$amount, $to]); $pdo->commit(); echo "Funds transferred successfully"; } catch (PDOException $e) { $pdo->rollBack(); echo "Transaction failed: " . $e->getMessage(); }
这演示了在事务中使用预处理语句的安全的资金转账。两个更新要么一起成功,要么一起失败。如果任何操作失败,rollBack 会撤销更改。始终对多步操作使用事务。
最佳实践
- 始终使用预处理语句: 用于所有带参数的 SQL。
- 选择命名参数: 用于具有许多参数的复杂查询。
- 指定参数类型: 使用 bindParam 或 bindValue 时。
- 重用语句: 用于使用不同值的多次执行。
- 错误处理: 始终捕获 PDOException 以处理数据库错误。
来源
本教程通过实际示例介绍了 PDO::prepare 方法,展示了其在不同数据库操作场景下的用法。
作者
列出 所有 PHP PDO 函数。