【问题标题】:Can't pass a constant variable by reference with $stmt->bind_param()?不能通过 $stmt->bind_param() 引用传递常量变量?
【发布时间】:2011-05-25 19:53:02
【问题描述】:

这是我的代码 sn-p:

private function add_user_limit()
{
    global $mysqli;
    $stmt = $mysqli->prepare("INSERT INTO `user_limits` (user_ip, downloads_left) VALUES (?, ?)");
    $stmt->bind_param("si", $this->user_ip, DEFAULT_USER_LIMIT);
    $stmt->execute();
    if($stmt->affected_rows == 0)
        throw new Exception("Couldn't add new user to the user_limits table");
    $stmt->close();
    $this->downloads_left = DEFAULT_USER_LIMIT;
}

DEFAULT_USER_LIMIT 被定义为8,但是使用上面的代码我得到了这个错误:

Fatal error: Cannot pass parameter 3 by reference in C:\xampp\htdocs\classes\limits.class.php on line 38

但如果我这样做:

private function add_user_limit()
{
    global $mysqli;
    $stmt = $mysqli->prepare("INSERT INTO `user_limits` (user_ip, downloads_left) VALUES (?, ?)");
    $user_limit = DEFAULT_USER_LIMIT; // For some reason we can't pass a constant to bind_param
    $stmt->bind_param("si", $this->user_ip, $user_limit);
    $stmt->execute();
    if($stmt->affected_rows == 0)
        throw new Exception("Couldn't add new user to the user_limits table");
    $stmt->close();
    $this->downloads_left = DEFAULT_USER_LIMIT;
}

它有效。我只是想知道为什么会发生这种情况,因为这对我来说真的没有意义。我看不出bind_param() 不能将常量变量作为参数的任何原因。

谢谢!

【问题讨论】:

  • 我为您使用参数化查询而鼓掌。在这方面,您比 99% 的 SQL 开发人员要好。但是,您可能在这里有点过分了:将常量绑定为参数是没有意义的,因为它不是用户输入。它总是安全的,除非您有目的地定义常量以包含 SQL 注入(出于某种原因)。简而言之,只需将您的常量直接连接到查询字符串中。至于您的问题,“原因” bind_param() 只能引用只是一个愚蠢的设计限制。没有真正的“理由”。就是这样
  • 尽管如此,我并不是在暗示从不绑定一个常量的理由。对不起,如果它看起来那样。正当理由可能包括:更好的可读性、更好的程序流程、效率(向 SQL 服务器发送更少的字节)、程序员的偏好。只是安全性不是绑定常量的原因。干杯。
  • @Lakey 感谢您的评论。 将常量绑定为参数是没有意义的,因为它不是用户输入。它总是安全的,除非您有目的地定义常量以包含 SQL 注入(出于某种原因)。简而言之,只需将您的常量直接连接到查询字符串中这行就是我的答案。

标签: php mysqli constants


【解决方案1】:

很简单,这是因为您不能通过引用传递常量,这样做没有意义,因为它是不可变的。顺便说一句,常量不是变量。它就在名称中。

【讨论】:

  • 不要忘记通过引用传递的第二个目的:避免移动大数据......它不必用于编辑,在 C++ 中很好地看到,其中 const 引用经常用作函数参数...... .
  • 是的,但这是 PHP,它采用了“写时复制”机制,这意味着,只要您不修改值,您就一直有效地通过引用传递.您可以通过编写带有大变量的脚本,然后分配副本,并在修改这些副本之前和之后检查内存使用情况来亲眼看到这一点。
  • 我知道并且它不会改变我所说的任何东西:),似乎你不知道通过引用传递的第二个目的 - 这个评论是给你的,不是给 OP 的 :)
【解决方案2】:

Mysqli 的 bind_param 是这样定义的:

bind_param ( string $types , mixed &$var1 [, mixed &$... ] )

说明

& 表示变量是通过引用传递的,因为 PHP 中的常量(例如DEFAULT_USER_LIMIT)不能以这种方式引用,所以它们只能作为值传递,因为它们就是这样。

因此,如果您有一个强制通过引用传递的函数,首先您必须将常量的值存储到一个变量并传递该变量(就像您所做的那样......)

现代解决方案 - 只需 use PDO

如果你可以使用 PDO 接口并且不需要通过引用传递值,
只用PDObindValue() + PDO 在常见情况下使用方式和Mysqli几乎一样。

public bool PDOStatement::bindValue ( mixed $parameter , mixed $value [, int $data_type = PDO::PARAM_STR ] )

如果您仍然需要通过引用传递,PDO 也有一个 bindParam()

public bool PDOStatement::bindParam ( mixed $parameter , mixed &$variable [, int $data_type = PDO::PARAM_STR [, int $length [, mixed $driver_options ]]] )

【讨论】:

    【解决方案3】:

    下面的东西可以通过引用传递:

    • 变量,即 foo($a)
    • 新语句,即 foo(new foobar())
    • 从函数返回的引用

    不应通过引用传递其他表达式,因为结果未定义

    http://php.net/manual/en/language.references.pass.php

    另外,

    mysqli_stmt_bind_param() 要求参数通过引用传递,而 call_user_func_array() 可以接受可以表示引用或值的变量列表作为参数。

    http://php.net/manual/en/mysqli-stmt.bind-param.php

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-16
      • 1970-01-01
      • 1970-01-01
      • 2013-06-21
      • 1970-01-01
      • 1970-01-01
      • 2011-03-14
      • 2019-05-10
      相关资源
      最近更新 更多