ZetCode

PHP PDOStatement 类

最后修改于 2025 年 4 月 19 日

PDOStatement 类代表一个预处理语句及其执行后的结果集。它提供了绑定参数、执行查询和获取结果的方法。

基本定义

PDOStatement 是一个表示预处理语句及其结果的类。它由 PDO::preparePDO::query 方法返回。

该类提供了用于绑定参数、执行语句、获取结果和检索结果集元数据的方法。

基本查询执行

此示例显示了如何使用 PDOStatement 执行简单查询。

pdo_basic_query.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->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 方法将每一行检索为一个关联数组。循环一直持续到处理完所有行。

带位置参数的预处理语句

这演示了如何使用带问号占位符的预处理语句。

pdo_positional_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('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 注入。

预处理语句中的命名参数

这展示了如何使用命名参数来使预处理语句更具可读性。

pdo_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('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 方法显式绑定参数。

pdo_bind_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 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 方法获取数据的各种方式。

pdo_fetch_formats.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->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。

pdo_transactions.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 = ?');
    
    $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 在失败时取消事务。

处理大型结果集

这演示了如何有效地处理大型结果集。

pdo_large_results.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 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()。这可以减少内存使用。游标方法允许随机访问行。

最佳实践

来源

PHP PDOStatement 文档

本教程涵盖了 PDOStatement 类,并通过实际示例展示了不同场景下的数据库操作。

作者

我叫 Jan Bodnar,我是一名热情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。至今,我已撰写了 1400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出 所有 PHP PDO 函数