【问题标题】:PDO bindParam not working in loopPDO bindParam 不能循环工作
【发布时间】:2023-03-11 11:41:01
【问题描述】:

我无法让 bindParam 在 foreach 循环内工作。如果我在循环之外使用 bindParam 或将值硬编码到 sql 查询中,一切都会完美运行。根据this page,建议改用bindValue。但是,当我使用 bindValue 时,它​​说在 bindValue 中使用的三个变量是未定义的。显然他们在这一点上。我做错了什么?

<?php

    $found_update = false;

    $installed_groups = array(
        array(
            "group_id" => 14,
            "version" => "1.0.7"
        )
    );



    $sql = "select id from testing_set where group_id = :GROUP_ID
        and (
            substring_index(substring_index(version, '.', 2), '.', -1) > :INSTALLED_VERSION_NUM_1 OR
            substring_index(substring_index(version, '.', 3), '.', -1) > :INSTALLED_VERSION_NUM_2
        )
        order by created desc limit 1";

    try {
        $dbh = new PDO("mysql:host=localhost; dbname=".DBNAME, DBUSER, DBPWD);

            $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

            $stmt = $dbh->prepare($sql);

            $stmt->bindParam(":GROUP_ID", $installed_group['group_id'], PDO::PARAM_INT);
            $stmt->bindParam(":INSTALLED_VERSION_NUM_1", $installed_version_parts[1], PDO::PARAM_INT);
            $stmt->bindParam(":INSTALLED_VERSION_NUM_2", $installed_version_parts[2], PDO::PARAM_INT);

            foreach ($installed_groups as $installed_group){

                $installed_version_parts = explode('.', $installed_group['version']);

                $stmt->execute();
                $data = $stmt->fetch(PDO::FETCH_ASSOC);

                if (!empty($data)){
                    $found_update = true;
                    break;
                }
        }

        echo "Found: $found_update\n";

    }
    catch(PDOException $e) {
        http_response_code(404);
        die();

    }

我的预期结果是它在终端上显示“找到:1”。现在的样子,当它应该为真时,它的值为假。

解决方案:

原来这里有两个问题。我通过在我的 bindParam 中使用基本变量而不是数组来遵循 IncredibleHat 的回答。这有助于解决第一个问题,但另一个问题是我需要将一些数据类型转换为 int:

$pt1 = (int)$installed_version_parts[1];

我原以为 PDO::PARAM_INT 正在为我做这件事,但事实并非如此。

【问题讨论】:

  • 绑定实际变量。
  • @IncredibleHat 是的,但是绑定应该在循环之外完成,而变量直到循环中才存在。这是一个陷阱 22。
  • 这看起来应该可以工作,如果explode 产生一个至少有3 个元素的数组,但是尝试一个像list($z, $one, $two) = explode(.....) 这样的临时变量并在绑定调用中使用它们。还有error_reporting(E_ALL); ini_set('display_errors', '1');
  • 我认为你应该在循环中绑定并在循环内执行。有了你所拥有的,你应该得到一个未定义的变量,因为这些变量只在循环内可用
  • 我遇到的问题是试图将绑定参数(引用)绑定到$array['key'] 之类的东西......它会抛出未定义的键。而且它是一个数组项,而不是一个变量。您可以只传递三个项目的执行数组:$stmt-&gt;execute(array($installed_group['group_id'],$installed_version_parts[1],$installed_version_parts[2])); 并完全取消 bindParam。

标签: php pdo bindparam


【解决方案1】:

尝试将bindParam 指向$array['key'] 之类的数组元素会导致一些问题,因为它被绑定为引用,但不是。它,只是没有那样做。

所以三种方式:

$stmt = $dbh->prepare($sql);
// bind to variables that can be a reference
$stmt->bindParam(":GROUP_ID", $id, PDO::PARAM_INT);
$stmt->bindParam(":INSTALLED_VERSION_NUM_1", $pt1, PDO::PARAM_INT);
$stmt->bindParam(":INSTALLED_VERSION_NUM_2", $pt2, PDO::PARAM_INT);
foreach ($installed_groups as $installed_group){
        $installed_version_parts = explode('.', $installed_group['version']);
        // assign the referenced vars their new value before execute
        $id = $installed_group['group_id'];
        $pt1 = $installed_version_parts[1];
        $pt2 = $installed_version_parts[2];
        $stmt->execute();
}

或者:(效率较低)

$stmt = $dbh->prepare($sql);
foreach ($installed_groups as $installed_group){
        $installed_version_parts = explode('.', $installed_group['version']);

        // use bindValue (not bindParam) INSIDE the loop
        // bindValue doesn't set them by reference, so any value expression works
        $stmt->bindValue(":GROUP_ID", $installed_group['group_id'], PDO::PARAM_INT);
        $stmt->bindValue(":INSTALLED_VERSION_NUM_1", $installed_version_parts[1], PDO::PARAM_INT);
        $stmt->bindValue(":INSTALLED_VERSION_NUM_2", $installed_version_parts[2], PDO::PARAM_INT);
        $stmt->execute();
}

或者:

$stmt = $dbh->prepare($sql);
foreach ($installed_groups as $installed_group){
        $installed_version_parts = explode('.', $installed_group['version']);

        // pass them on execute directly
        $stmt->execute(array(':GROUP_ID'=>$installed_group['group_id'],
                             ':INSTALLED_VERSION_NUM_1'=>$installed_version_parts[1],
                             ':INSTALLED_VERSION_NUM_2'=>$installed_version_parts[2]));
}

【讨论】:

  • 第二个选项效率较低,因为您每次都必须重新绑定,因此第一个或第三个选项是最好的,我是否正确?
  • 正确(用于大型操作)。虽然有几个查询没有注意到它。
  • 尝试第一个选项,它只有在我将 $pt1 和 $pt2 转换为 int 时才有效:$pt1 = (int)$installed_version_parts[1]; 这是为什么? PDO::PARAM_INT 不应该解决这个问题吗?
  • 你会认为它会......但它强制它应该是一个 int,而不是翻译它。以下是关于选角的简介:stackoverflow.com/a/19751442/2960971(阅读该答案的论点很重要,哈哈)。
猜你喜欢
  • 1970-01-01
  • 2015-03-14
  • 1970-01-01
  • 1970-01-01
  • 2012-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-21
相关资源
最近更新 更多