ZetCode

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 与位置参数的最简单用法。

basic_prepare.php
<?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 语句更具可读性和可维护性。

named_params.php
<?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 提供了对参数绑定的更多控制。

explicit_binding.php
<?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 通过值绑定。两种方法都提供类型安全。

具有多个执行的预处理语句

预处理语句可以与不同的值多次执行。

multiple_executions.php
<?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 查询一起用于安全的数据检索。

fetch_data.php
<?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。

like_clause.php
<?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 事务无缝配合,以确保数据完整性。

transaction.php
<?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 会撤销更改。始终对多步操作使用事务。

最佳实践

来源

PHP PDO::prepare 文档

本教程通过实际示例介绍了 PDO::prepare 方法,展示了其在不同数据库操作场景下的用法。

作者

我叫 Jan Bodnar,是一位充满热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。至今,我已撰写了 1,400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出 所有 PHP PDO 函数