【问题标题】:Variable parameter/result binding with prepared statements可变参数/结果与准备好的语句绑定
【发布时间】:2010-09-05 23:22:33
【问题描述】:

在我即将结束的一个项目中,我为 PHP 编写并实现了一个对象关系映射解决方案。在怀疑者和梦想家大声喊出“到底怎么回事?”之前,放松一下——我还没有找到一种方法来使后期的静态绑定起作用——我只是在以尽可能最好的方式解决它。

无论如何,我目前没有使用准备好的语句进行查询,因为我想不出一种方法来将可变数量的参数传递给bind_params()bind_result() 方法。

你问,为什么我需要支持可变数量的参数?因为我的模型的超类(将我的解决方案想象成一个被破解的 PHP ActiveRecord 崇拜者)是定义查询的地方,所以例如 find() 方法不知道它需要绑定多少参数.

现在,我已经考虑过构建一个参数列表并将一个字符串传递给 eval(),但我不太喜欢这种解决方案——我宁愿只实现自己的安全检查并传递语句.

有人对如何完成这项工作有任何建议(或成功案例)吗?如果你能帮我解决第一个问题,也许我们可以解决绑定结果集(如果涉及到确定表结构的初始查询,我怀疑这会更困难,或者至少更耗费资源)。

【问题讨论】:

    标签: php mysql mysqli


    【解决方案1】:

    在 PHP 中,您可以使用 call_user_func_array 将可变数量的参数传递给函数或方法。一个方法的例子是:

    call_user_func_array(array(&$stmt, 'bindparams'), $array_of_params);
    

    将调用该函数,并将数组中的每个成员作为其自己的参数传递。

    【讨论】:

    • 我觉得函数名应该是bind_param而不是bindparams。至少在我的mysqli 版本中,我使用它输入$stmt->bind_param(),而不是$stmt->bindparams()。干杯!
    【解决方案2】:

    更现代的动态绑定参数的方法是通过 splat/spread 运算符 (...)。

    假设:

    • 您有一个非空值数组要绑定到您的查询,并且
    • 您的数组值在查询上下文中被适当地处理为字符串类型值,并且
    • 您的输入数组称为$values

    PHP5.6 及更高版本的代码:

    $stmt->bind_param(str_repeat('s', count($values)), ...$values);
    

    事实上,如果您愿意,所有提供给bind_param() 的参数都可以使用 splat/spread 运算符解包——数据类型字符串只需是数组的第一个元素。

    array_unshift($values, str_repeat('s', count($values)));
    $stmt->bind_param(...$values);
    

    【讨论】:

      【解决方案3】:

      您必须确保 $array_of_params 是指向变量的链接的数组,而不是值本身。应该是:

      $array_of_params[0] = &$param_string; //link to variable that stores types
      

      然后……

      $param_string .= "i";
      $user_id_var = $_GET['user_id'];//
      $array_of_params[] = &$user_id_var; //link to variable that stores value
      

      否则(如果它是值数组)你会得到:

      PHP 警告:mysqli_stmt::bind_param() 的参数 2 应为参考


      再举一个例子:

      $bind_names[] = implode($types); //putting types of parameters in a string
      for ($i = 0; $i < count($params); $i++)
      {
         $bind_name = 'bind'.$i; //generate a name for variable bind1, bind2, bind3...
         $$bind_name = $params[$i]; //create a variable with this name and put value in it
         $bind_names[] = & $$bind_name; //put a link to this variable in array
      }
      

      和 BOOOOOM:

      call_user_func_array( array ($stmt, 'bind_param'), $bind_names); 
      

      【讨论】:

        【解决方案4】:

        我不允许编辑,但我相信代码

        call_user_func_array(array(&$stmt, 'bindparams'), $array_of_params);
        

        $stmt 前面的引用不是必须的。由于$stmt 是对象,bindparams 是该对象中的方法,因此不需要引用。应该是:

        call_user_func_array(array($stmt, 'bindparams'), $array_of_params);
        

        有关更多信息,请参阅Callback Functions 上的 PHP 手册。"

        【讨论】:

          【解决方案5】:
          call_user_func_array(array(&$stmt, 'bindparams'), $array_of_params);
          

          在我的环境中对我不起作用,但这个答案让我走上了正轨。实际起作用的是:

          $sitesql = '';
          $array_of_params = array();
          foreach($_POST['multiselect'] as $value){
              if($sitesql!=''){
                  $sitesql .= "OR siteID=? ";
                  $array_of_params[0] .= 'i';
                  $array_of_params[] = $value;
              }else{
                  $sitesql = " siteID=? ";
                  $array_of_params[0] .= 'i';
                  $array_of_params[] = $value;
              }
          }
          
          $stmt = $linki->prepare("SELECT IFNULL(SUM(hours),0) FROM table WHERE ".$sitesql." AND week!='0000-00-00'");
          call_user_func_array(array(&$stmt, 'bind_param'), $array_of_params);
          $stmt->execute();
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-09-27
            • 2013-06-16
            • 2013-10-05
            • 2019-11-09
            • 2013-12-13
            • 2016-08-30
            • 2016-09-04
            • 2016-05-22
            相关资源
            最近更新 更多