【问题标题】:Why I am getting Cannot pass parameter 2 by reference error when I am using bindParam with a constant value?当我使用具有常量值的 bindParam 时,为什么会出现无法通过引用传递参数 2 的错误?
【发布时间】:2010-11-26 09:07:51
【问题描述】:

我正在使用此代码,我感到非常沮丧:

try {
    $dbh = new PDO('mysql:dbname=' . DB . ';host=' . HOST, USER, PASS);
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $dbh->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES 'utf8'");
}
catch(PDOException $e)
{
    ...
}
$stmt = $dbh->prepare('INSERT INTO table(v1, v2, ...) VALUES(:v1, :v2, ...)');
$stmt->bindParam(':v1', PDO::PARAM_NULL); // --> Here's the problem

PDO::PARAM_NULL, null, '',全部失败并抛出这个错误:

致命错误:无法通过 /opt/...中的引用传递参数 2...

【问题讨论】:

    标签: php mysql pdo null sql-insert


    【解决方案1】:

    你需要使用bindValue,而不是bindParam

    bindParam 通过引用获取变量,并且在调用bindParam 时不引入值。我在 PHP 文档的评论中发现了这一点:

    bindValue(':param', null, PDO::PARAM_INT);
    

    附:您可能很想这样做bindValue(':param', null, PDO::PARAM_NULL);,但它并不适用于所有人(感谢 Will Shaver 的报告。)

    【讨论】:

    • 我不确定这两者之间的区别,但我会调查一些。谢谢,你的回答也很棒。
    • 我认为这可能是比我的更好的答案(如果它确实有效)
    • 我在 MySql 5.1.53 上遇到了 PDO::PARAM_NULL 问题,但是带有 null 值的 PDO::PARAM_INT 效果很好。
    • Odin:我认为最重要的部分是传递所有三个参数:)。在 ign 的问题中,他将 PDO::PARAM_NULL 作为值传递,而不是作为类型(并且根本没有传递类型。)
    • 仅供参考:在大多数情况下,使用 bindValue() 而不是 bindParam() 完全没问题;适用于所有内容,而不仅仅是 NULL 值。我想不出你需要将参数绑定到 PHP 变量的引用的单一情况 - 但这就是 bindParam() 所做的。
    【解决方案2】:

    基于其他答案,但更清楚地了解如何实际使用此解决方案。

    例如,如果您有一个空字符串作为时间值,但您想将其保存为空值:

      if($endtime == ""){
        $db->bind(":endtime",$endtime=NULL,PDO::PARAM_STR);
      }else{
        $db->bind("endtime",$endtime);
      }
    

    请注意,对于时间值,您将使用 PARAM_STR,因为时间存储为字符串。

    【讨论】:

      【解决方案3】:

      就我而言,我正在使用:

      • SQLite,

      • 用占位符准备语句来处理未知数量的字段,

      • 用户发送的 AJAX 请求,其中 everything 是一个字符串,并且没有像 NULL 值这样的东西和

      • 我迫切需要插入NULLs,因为这不会违反外键约束(可接受的值)。

      假设,现在用户发送邮件:$_POST[field1],其值为value1,可以是空字符串"""null""NULL"

      首先我声明:

      $stmt = $this->dbh->prepare("INSERT INTO $table ({$sColumns}) VALUES ({$sValues})");
      

      {$sColumns} 就像 field1, field2, ...{$sValues} 是我的占位符 ?, ?, ...

      然后,我收集我的$_POST 与数组$values 中的列名相关的数据替换为NULLs:

        for($i = 0; $i < \count($values); $i++)
           if((\strtolower($values[$i]) == 'null') || ($values[$i] == ''))
              $values[$i] = null;
      

      现在,我可以执行了:

      $stmt->execute($values);
      

      以及其他绕过外键约束。

      另一方面,如果空字符串更有意义,那么您必须检查该字段是否是外键的一部分(更复杂)。

      【讨论】:

        【解决方案4】:

        试试这个。

        $stmt->bindValue(':v1', null, PDO::PARAM_NULL); // --> insert null
        

        【讨论】:

        • 在尝试回答这样一个老问题之前,您应该先阅读其他答案。可能已经回答过了。
        【解决方案5】:

        我遇到了同样的问题,我发现这个解决方案可以与 bindParam 一起使用:

            bindParam(':param', $myvar = NULL, PDO::PARAM_INT);
        

        【讨论】:

          【解决方案6】:

          如果您只想在valueempty'' 时插入NULL,但在value 可用时插入。

          A) 使用 POST 方法接收表单数据,并使用这些值调用函数 insert。

          insert( $_POST['productId'], // Will be set to NULL if empty    
                  $_POST['productName'] ); // Will be to NULL if empty                                
          

          B) 评估用户是否未填写字段,如果是则插入 NULL

          public function insert( $productId, $productName )
          { 
              $sql = "INSERT INTO products (  productId, productName ) 
                          VALUES ( :productId, :productName )";
          
              //IMPORTANT: Repace $db with your PDO instance
              $query = $db->prepare($sql); 
          
              //Works with INT, FLOAT, ETC.
              $query->bindValue(':productId',  !empty($productId)   ? $productId   : NULL, PDO::PARAM_INT); 
          
              //Works with strings.
              $query->bindValue(':productName',!empty($productName) ? $productName : NULL, PDO::PARAM_STR);   
          
              $query->execute();      
          }
          

          例如,如果用户没有在表单的productName 字段中输入任何内容,那么$productName 将是SETEMPTY。所以,你需要检查它是否是empty(),如果是,则插入NULL

          在 PHP 5.5.17 上测试

          祝你好运,

          【讨论】:

          • 或者,您可以在查询字符串中使用 MySQL 的 IFNULL() 函数。像这样:$sql = "INSERT INTO products ( productId, productName ), VALUES ( IFNULL(:productId, NULL), IFNULL(:productName, NULL) )";
          • 我喜欢你的解决方案的清洁度。我刚刚对其进行了测试,但不幸的是,当用户没有在输入上写任何内容时,它会插入空字符串而不是 NULL。这只是一个偏好问题,但我宁愿使用 NULL 而不是空字符串。
          【解决方案7】:

          对于还有问题的(不能通过引用传递参数2),定义一个null值的变量,而不是仅仅将null传递给PDO:

          bindValue(':param', $n = null, PDO::PARAM_INT);
          

          希望这会有所帮助。

          【讨论】:

            【解决方案8】:

            在 MySQL 中使用 INTEGER 列(可以是 NULL)时,PDO 有一些(对我而言)意想不到的行为。

            如果使用$stmt-&gt;execute(Array),则必须指定字面量NULL,不能通过变量引用给出NULL。 所以这行不通:

            // $val is sometimes null, but sometimes an integer
            $stmt->execute(array(
                ':param' => $val
            ));
            // will cause the error 'incorrect integer value' when $val == null
            

            但这会起作用:

            // $val again is sometimes null, but sometimes an integer
            $stmt->execute(array(
                ':param' => isset($val) ? $val : null
            ));
            // no errors, inserts NULL when $val == null, inserts the integer otherwise
            

            在 MySQL 5.5.15 和 PHP 5.4.1 上试过这个

            【讨论】:

            • $stmt->execute(array( ':param' => !empty($val) ? $val : null ));使用 !empty 因为对于空字符串,您还想在数据库中设置 null
            • @ShehzadNizamani 仅当列类型为整数时,如在他的示例中,是的。但除此之外,isset()NULL 的相关性更好。空字符串也是一个值。
            • @ShehzadNizamani 0 的价值呢? empty() 将为它返回 true。并且您的代码将存储 null 而不是合法的 0 整数值
            【解决方案9】:

            使用bindParam() 时,您必须传入一个变量,而不是常量。因此,在该行之前,您需要创建一个变量并将其设置为null

            $myNull = null;
            $stmt->bindParam(':v1', $myNull, PDO::PARAM_NULL);
            

            如果你尝试过,你会得到同样的错误信息:

            $stmt->bindParam(':v1', 5, PDO::PARAM_NULL);
            

            【讨论】:

            • 你说得对,我刚刚意识到我以前在我的代码中做过,$null = PDO::PARAM_NULL;谢谢。
            • 在这种情况下最好使用 bindValue() ,如果你要制作占位符的话。 bindParam() 本来是打算执行一个查询,然后改变变量重新执行,不再绑定参数。 bindValue() 立即绑定,bindParam() 仅在执行时绑定。
            • 我发现 $myNull = null 行中的 null 必须是小写的。 $myNull = NULL 不起作用。
            猜你喜欢
            • 1970-01-01
            • 2012-10-17
            • 1970-01-01
            • 2013-03-07
            • 1970-01-01
            • 2023-02-25
            • 2014-01-13
            • 2018-02-21
            相关资源
            最近更新 更多