【问题标题】:multiple calls to $stmt->bind_param多次调用 $stmt->bind_param
【发布时间】:2016-08-09 18:14:44
【问题描述】:

我想构建一个代码,以这种格式获取$bindParam 变量:

$bindParams = [$type1 => $param1, $type2 => $param2, ... ]

我想构建一些代码,将参数动态添加到准备好的语句中。
这是我到目前为止构建的代码:

$mysql = new mysqli("localhost", "root", "", "db1");
$stmt = $mysql->prepare($sql);
foreach($bindParams as $type => $data) {
    $stmt->bind_param($type, $data);
}
$stmt->execute();
$result = $stmt->get_result();
// and after perhaps twiddling with the result set, but this is not the case .....

对于您的实例

$sql = "INSERT INTO table1 (name, age) VALUES (?,?);"

$bindParams = ["s" => "hello", "i" => 15] 

这并不总是具有这种结构,它可以更改为例如$bindParams = ["s" => "hello", "i" => 15, "d" => 22.5],因此$sql 会分别更改。

在编译器第一次转到$stmt->bind_param($type, $data); 之后,firefox 会刷新此错误:

警告:mysqli_stmt::bind_param(): 变量数与第 23 行 D:\PHP\tr.php 中准备好的语句中的参数数不匹配

here at the end of the page. 所述,我知道 PDO 支持,但也许正如您所料,我不是 PDO 的粉丝,所以 ;)
我的另一个选择是使用 php 中可用的eval() 变通办法,但这不是我可能想到的。

还有其他方法吗?

【问题讨论】:

  • 显示您的$query 和您的$bindParams。如果你有超过 1 个任何类型,它将相互覆盖,所以你总是会得到任何类型的 1 个。
  • 您不能将一个参数放在同一个呼叫的 2 个不同呼叫上。起初,每个你传递的名字都像 INSERT INTO table1 (name, age) VALUES ("hello", )INSERT INTO table1 (name, age) VALUES (, 15) 你需要把 2 个值放在同一个
  • @ManuelRodriguezGil 我知道.. 是的.. 有什么解决方法吗?因为我不能把这些价值观放在一个电话里。我从函数调用中将其作为数组接收。
  • 如果$bindParams 始终具有相同的结构,您可以这样做:$stmt->bind_param('si', $bindParams["s"], $bindParams["i"]);
  • @ManuelRodriguezGil 不,这正是问题所在;)例如,可以调用我的函数并将此值传递给 $bindParams$bindParams = ["s" => "hello", "i" => 15, "s" => "world"]$sql 分别更改。

标签: php mysqli prepared-statement bindparam


【解决方案1】:

我遇到了同样的问题,找到了一个更简单的答案:

$array_of_values = array( "Brasil", "Argentina" );
$types = "ss";
$mysqli_stmt->bind_param( $types, ...$array_of_values );

这称为“参数解包”,从 PHP 5.6 开始可用

【讨论】:

  • 自从我为这个问题苦苦挣扎以来已经有很长时间了。但谢谢你的想法。我将应用您的解决方案,并在我再次遇到问题时查看它是否有效。
【解决方案2】:

遗憾的是 mysqli 不支持这个。一遍又一遍地调用函数会覆盖值,所以当你显然有更多参数时,你只绑定一个参数。

有几种方法可以解决这个问题

  1. 切换到 PDO。您可以使用它为每个函数调用进行一个绑定
  2. 使用call_user_func_array 将参数绑定为一个聚合

    $sqltype = '';
    $sqldata = [];
    foreach($bindParams as $type => $data) {
        $sqltype .= $type;
        $sqldata[] = &$data; // MUST be a reference
    }
    array_unshift($sqldata, $sqltype); // prepend the types
    call_user_func_array([$stmt, 'bind_param'], $sqldata);
    

【讨论】:

    【解决方案3】:

    我用这样的东西来做动态过程调用。

    示例调用:

        $mapi = new MySQLIAPI($con);
        $mapi->BeginProc();
        $mapi->AddParameter("user", $usern, "s");
        $mapi->AddParameter("email", $email, "s");
        $mapi->AddParameter("passwd", $pwd, "s");
        $id = $mapi->CallProc("ij_create_user");
        $id = $id[0];
    
        if(isset($id['mysql_error']) || isset($id["error"])){
          return "error";
        }
        return $id["id"];
    

    示例类:

    class MySQLIAPI
    {
        private $con = null;
        private $Variables = null;
        private $values = null;
        private $types = null;
        private $vQu = null;
        private $stmt = null;
        function __construct($dbc)
        {
            $this->con = $dbc;
                $this->Variables = [];
            $this->values = [];
            $this->types = [];
            $this->vQu = [];
        }
        function BeginProc()
        {
            $this->stmt = $this->con->stmt_init(); // initialize statement
        }
    
        function AddParameter($key, $val, $type)
        {
            $this->Variables[] = "@" . $key;
            $this->values[]    = $val;
            $this->types[]     = $type;
            $this->vQu[]       = "?";
        }
    
        //KeyPair is v = the value, t = the type s or d
        function CallProc($Proc) {
          $out_var = null;
    
          $call = "";
          if(sizeof($this->values) > 0)
            $call = "CALL ".$Proc."(".implode(",", (array)$this->vQu).")";
          else
            $call = "CALL ".$Proc."()";
    
         if($this->stmt->prepare($call));//call stored procedure with database server session variable
         {
           if(sizeof($this->values) > 0) {
             $params = array_merge(array(implode("", $this->types)), $this->values);
             call_user_func_array(array($this->stmt, 'bind_param'), $this->refValues($params));
           }
    
           $this->stmt->execute();
           $result = $this->stmt->get_result();
    
           /* Error Checking */
           $mySQLiError = mysqli_stmt_error($this->stmt);
           if ($mySQLiError != "") {
             $this->resetStmt();
             $this->stmt->close();
             $this->stmt = null;
             return array('mysql_error' => $mySQLiError);
           }
    
           while ($row = $result->fetch_array(MYSQLI_ASSOC))
           {
             $out_var[] = $row;
           }
           $result->free();
           while($this->stmt->more_results())
           {
             $this->stmt->next_result();
           }
    
           $this->resetStmt();
           $this->stmt->close();
           $this->stmt = null;
         }
    
         return $out_var;
        }
        private function refValues($arr)
        {
            if (strnatcmp(phpversion(), '5.3') >= 0) //Reference is required for PHP 5.3+
                {
                $refs = array();
                foreach ($arr as $key => $value)
                    $refs[$key] =& $arr[$key];
                return $refs;
            }
            return $arr;
        }
        private function resetStmt()
        {
            //Reset Params
            $this->Variables = array();
            $this->values    = array();
            $this->types     = array();
            $this->vQu       = array();
        }
    }
    

    【讨论】:

    • 那里的mapi 是什么:|请验证您的答案
    • 抱歉 @TechJS mapi 只是 MySQLIAPI 类实例的变量
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-23
    • 1970-01-01
    • 2013-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多