如何重用PDOStatement准备?

时间:2014-01-23 10:18:59

标签: php pdo prepared-statement

我进行了搜索,但找不到任何令人满意的内容

想象一下:

<?php

$connection = new \PDO($dsn, $user, $pass);

$stmt1 = $connection->prepare("
    SELECT
        *
    FROM
        table
    WHERE
            a = :a
    AND     b = :b
    AND     c = :c
    AND     d = :d
    AND     search LIKE :search
");
$stmt1->bindValue(":a", $a);
$stmt1->bindValue(":b", $b);
$stmt1->bindValue(":c", $c);
$stmt1->bindValue(":d", $d);

$stmt2 = clone $stmt1;

$stmt1->bindValue(":search", "a%");
$stmt2->bindValue(":search", "b%");

$stmt1->execute();
$stmt2->execute();

while(($r1 = $stmt1->fetchObject()) && ($r2 = $stmt2->fetchObject()))
    echo $r1->foo . " " . $r2->foo . "\n";
}

我可以做这样的事吗?我如何clone /重用PDOStatement实例并在其原始实例的同时使用它?

不要说“使用UNION,这不是我的问题:P

提前谢谢。

2 个答案:

答案 0 :(得分:6)

这不是准备重复使用的语句。重用预准备语句的想法是连续,而不是并发

所以你可以这样做:

$connection = new \PDO($dsn, $user, $pass);

$stmt = $connection->prepare("
    SELECT *
    FROM table
    WHERE a = :a
      AND b = :b
      AND c = :c
      AND d = :d
      AND search LIKE :search
");

$stmt->bindValue(":a", $a);
$stmt->bindValue(":b", $b);
$stmt->bindValue(":c", $c);
$stmt->bindValue(":d", $d);

foreach (["a%", "b%"] as $search) {
    $stmt->bindValue(":search", $search);
    $stmt->execute();

    while($r = $stmt->fetchObject()) {
        echo $r->foo . "\n";
    }

    $stmt->closeCursor();
}

如果要同时处理多个结果集(至少使用MySQL),则需要执行以下操作之一:

  • 使用一组适当的UNION / JOIN来创建单个结果集。
  • 将结果集缓冲到内存中,并在获得所有可用数据后再次迭代它们。
  • 创建多个连接 - 每个连接不能有多个打开的语句游标 ,但您可以拥有多个打开的连接。

如果您想使用多个连接,您的代码将变为:

$query = "
    SELECT *
    FROM table
    WHERE a = :a
      AND b = :b
      AND c = :c
      AND d = :d
      AND search LIKE :search
";

$connection1 = new \PDO($dsn, $user, $pass);
$connection2 = new \PDO($dsn, $user, $pass);

$stmt1 = $connection1->prepare($query);
$stmt1->bindValue(":a", $a);
$stmt1->bindValue(":b", $b);
$stmt1->bindValue(":c", $c);
$stmt1->bindValue(":d", $d);
$stmt1->bindValue(":search", "a%");

$stmt2 = $connection2->prepare($query);
$stmt2->bindValue(":a", $a);
$stmt2->bindValue(":b", $b);
$stmt2->bindValue(":c", $c);
$stmt2->bindValue(":d", $d);
$stmt2->bindValue(":search", "b%");

$stmt1->execute();
$stmt2->execute();

while(($r1 = $stmt1->fetchObject()) && ($r2 = $stmt2->fetchObject()))
    echo $r1->foo . " " . $r2->foo . "\n";
}

$stmt1->closeCursor();
$stmt2->closeCursor();

答案 1 :(得分:1)

听起来你正在寻找一个准备好的语句的抽象,它可以随身携带它自己的参数。

当您通过遍历它实际消耗每个结果时,添加一个知道如何遍历这样一个参数化预处理语句的Iterator看起来是合适的。

然而,这个建议不是PDO的一部分,所以你需要自己编写它(但是这也可能会阻止用PDO代码重复自己你甚至可能会对实际创建和执行语句,这样也可以为延迟加载数据创造一些好处。)