Php 速记PDO查询

Php 速记PDO查询,php,mysql,pdo,Php,Mysql,Pdo,目前,为了使用PDO执行查询,我使用以下代码行: $sql = "SELECT * FROM myTable WHERE id = :id"; $stmt = $conn->prepare($sql); $stmt->bindParam(':id', $id); $stmt->execute(); $result = $stmt->fetchAll(PDO::FETCH_ASSOC); 经过一些研究,我发现了一种执行同一命令的较短方法: $stmt_test = $co

目前,为了使用PDO执行查询,我使用以下代码行:

$sql = "SELECT * FROM myTable WHERE id = :id";
$stmt = $conn->prepare($sql);
$stmt->bindParam(':id', $id);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
经过一些研究,我发现了一种执行同一命令的较短方法:

$stmt_test = $conn->prepare("SELECT * FROM status WHERE status_id = ?");
$stmt_test->execute([$id])->fetchAll(PDO::FETCH_ASSOC);
$result = $stmt_test->fetchAll(PDO::FETCH_ASSOC);
从那时起,我想我可以使用以下代码将其缩短:

$stmt_test = $conn->prepare("SELECT * FROM status WHERE status_id = ?");
$result = $stmt_test->execute([$id])->fetchAll(PDO::FETCH_ASSOC);
但我得到了以下错误:

致命错误:对中的非对象调用成员函数fetchAll() /第20行的home/../index.php

问题:我为什么会出现此错误?根据我的理解,
$stmt\u test->execute([$id])
应该首先执行,然后执行
->fetchAll(PDO::FETCH\u ASSOC)
,然后从那里将数组返回到
$result
,但是由于发生了错误,我的逻辑一定有缺陷。我做错了什么?另外,是否有人知道更好的速记方法来执行上一个查询?

$stmt\u test->execute([$id])
返回一个值。也就是说

$result = $stmt_test->execute([$id])->fetchAll(PDO::FETCH_ASSOC);
这是无效的。相反,你应该这样做

$stmt_test->execute([$id]);
$result = $stmt_test->fetchAll(PDO::FETCH_ASSOC);

我相信PDO的
execute()
方法返回true或false。正如错误已经告诉您的那样:
fetchAll()
需要一个对象。使用三行代码是最短的方法


另一种选择是使用ORM,例如,它工作非常平稳,将为您节省大量时间。

您遇到的错误来自PDO的设计方式
PDOStatement::execute()
不返回语句,而是一个表示成功的布尔值。因此,您想要的快捷方式是不可能的

请参见中的函数定义


另外,让我补充一点,forEach()通常(并非总是)是一种代码味道,需要占用相对较多的内存,因为它必须将所有行存储为PHP值。

因此您已经得到了“为什么我会出现此错误”问题的答案,但没有得到“速记PDO查询”的答案

为此,我们需要一种叫做“编程”的东西

关于编程,一件有趣的事情是我们不局限于现有的工具,就像其他职业一样。通过编程,我们总是可以创建自己的工具,然后开始使用它,而不是一整套旧工具

而面向对象编程尤其擅长于此,因为我们可以利用现有的对象,只添加一些功能,其余的保持不变

例如,假设我们想要一种在PDO中运行准备好的查询的速记方法。我们只需要用一种新的速记方法扩展PDO对象。最困难的部分是为新方法命名

剩下的很简单:您只需要几行代码

class MyPDO extends PDO
{
    public function run($sql, $bind = NULL)
    {
        $stmt = $this->prepare($sql);
        $stmt->execute($bind);
        return $stmt;
    }
}
这是您需要的所有代码。您可以将其存储在存储数据库凭据的同一文件中。请注意,此添加不会以任何方式影响您现有的代码——它保持完全相同,您可以像往常一样继续使用所有现有的PDO功能

现在您只需更改PDO构造函数中的2个字母,将其称为

$conn = new MyPDO(...the rest is exactly the same...);
您可以立即开始使用闪亮的新工具:

$sql = "SELECT * FROM myTable WHERE id = :id";
$result = $conn->run($sql, ['id' => $id])->fetchAll(PDO::FETCH_ASSOC);
或者,给它一点优化

$result = $conn->run("SELECT * FROM myTable WHERE id = ?", [$id])->fetchAll();
由于始终可以一次性设置默认获取模式,并且对于单个变量,命名占位符没有任何用处。与公认的答案相比,这段代码是一个真正的速记

$stmt_test = $conn->prepare("SELECT * FROM status WHERE status_id = ?");
$stmt_test->execute([$id]);
$result = $stmt_test->fetchAll(PDO::FETCH_ASSOC);
即使是到目前为止你得到的最好的答案

$result = $conn->prepare("SELECT * FROM status WHERE status_id = ?");
$result->execute([$id]);
更不用说后者并不总是可用的,因为它只适合获取数组。使用真正的速记,任何结果格式都是可能的:

$result = $conn->run($sql, [$id])->fetchAll(); // array
$result = $conn->run($sql, [$id])->fetch(); // single row
$result = $conn->run($sql, [$id])->fetchColumn(); // single value
$result = $conn->run($sql, [$id])->fetchAll(PDO::FETCH_*); // dozens of different formats

@johannes的可能重复项即使错误的名称相似,导致错误的情况也不同。Ah没有仔细阅读,将在下面给出答案。@johannes一切正常:)完美答案的可能重复项。我会在期限届满时接受这个答案。没有意识到
$stmt\u test
返回的是布尔值,因此
fetchAll
被应用于该返回值,而不是
$stmt\u test
本身。@Webeng我不认为这个答案完美,因为它不会使代码变得更短。哦,你建议我在($row=$stmt\u test->fetch)时改为
(PDO::FETCH_ASSOC)){…}
这样我就不会用我上面的代码做
foreach($result as…
)?PDO语句实现了可遍历,所以你可以做
foreach($stmt_test as…
(我必须承认,我不确定这使用的是哪种模式,可能是PDO::FETCH_二者)使用这种方法,你总是只需要在内存中保存当前元素,并对它进行一次迭代,而不是两次迭代,哪种方法是两次迭代的?xD我不确定我是否理解我所做的是两次迭代的代码,现在我真的很想知道hahah@webeng您可以在spe实例化时指定获取模式将第四个选项参数指定给构造函数,例如,
[PDO::ATTR_DEFAULT_FETCH_MODE=>PDO::FETCH_ASSOC]
“foreach是一种代码气味”-因此,为了消除这种气味,我将停止向模板传递数组,并在查询执行后立即开始回显HTML。好的建议,从现在起将使用它。哈哈,这是一个非常完整的答案,毫无疑问,这是值得尊敬的绿色复选标记谢谢。这个标记实际上不是给我的,而是给其他开发者的g代表速记PDO函数。我想,我的解决方案是唯一一个真正回答这个问题的方案,而不仅仅是承认这个问题。为PDO创建一个包装类似乎有点过头了,显然是为了创建一个简单地将两个方法组合成一个的方法。答案是没有更快的方法来执行准备好的语句sing PDO。这是一个很大的答案,但我必须同意你的看法。@JasonK它不是一个包装类。它是一个类扩展-对于OOP来说,这就像人类的呼吸一样自然。你会称呼吸为过度杀戮吗?@你的常识你会碰巧知道很多关于PDO/mysql中的事务吗?下面的问题在下面D