【问题标题】:Using bind_param with arrays and loops将 bind_param 与数组和循环一起使用
【发布时间】:2016-08-15 03:20:54
【问题描述】:

根据这个example 对于准备好的语句,我首先绑定参数,然后为参数设置值。

假设我有一个二维数组 $alias

$array1 = [
    'id' => 1,
    'tstamp' => 123456789,
    'alias' => '$alias',
];

$array2 = [
    'id' => 1,
    'tstamp' => 123456789,
    'alias' => '$alias2',

];

$alias = [$array1, $array2];

为什么这段代码有效

$insert = 'INSERT INTO abcdef VALUES (?,?,?)';
$insertStmt = $conn->prepare($insert);
foreach ($alias as $array) {
    $insertStmt->bind_param('iis', $array['id'], $array['tstamp'], $array['alias']);
    $insertStmt->execute();
}

这不是吗?

$insert = 'INSERT INTO abcdef VALUES (?,?,?)';
$insertStmt = $conn->prepare($insert);
$insertStmt->bind_param('iis', $array['id'], $array['tstamp'], $array['alias']);
foreach ($alias as $array) {
   $insertStmt->execute();
}

如果我必须一直绑定参数,那么流量会更多,不是吗?

【问题讨论】:

  • binding 基本上在占位符和绑定变量之间建立了一个引用。当您执行foreach() 时,$array 将在每次循环迭代时被删除/重新创建,因此您绑定到循环外的任何内容都将不再存在于循环内。
  • 好的,谢谢。如果我有像 $alias 这样的数组,有没有更好的连接方式?

标签: php mysql arrays mysqli prepared-statement


【解决方案1】:

bind_param() 通过引用特定的zval container 进行绑定。在循环的每次迭代中,都会为新的数组符号表分配其自己的 zval 容器。如果在绑定时 zval 容器不存在,它们将被创建。这可以用以下代码显示:

$insertStmt = $conn->prepare('INSERT INTO abcdef VALUES (?,?,?)');
$insertStmt->bind_param('sss', $array['id'], $array['tstamp'], $array['alias']);
var_dump($array);

输出:

array (size=3)
  'id' => null
  'tstamp' => null
  'alias' => null

即使我们没有在任何地方声明$array,绑定还是隐式地使用空值创建了它。绑定将继续指向这个空数组。

当然,当我们开始迭代别名数组时,$array 每次都会重新创建。我们绑定参数的旧数组符号表现在已经不存在了。我们没有将任何东西绑定到新数组。

要解决此问题,您只需将 bind_param() 移动到 foreach 循环内:

$insertStmt = $conn->prepare('INSERT INTO abcdef VALUES (?,?,?)');
foreach ($alias as $array) {
    // bind to the new zval containers every iteration
    $insertStmt->bind_param('sss', $array['id'], $array['tstamp'], $array['alias']);
    $insertStmt->execute();
}

【讨论】:

    【解决方案2】:

    如果我必须一直绑定参数还有很多 流量,不是吗?

    流量是在prepareexecute 事件上产生的。

    话虽如此,您可以重新安排您的 a little 以将 ->bind_param() 移到循环之外。更简单的方法是绑定变量而不是数组:

    $array1 = ['id' => 1, 'tstamp' => 123456789, 'alias' => '$array1'];
    $array2 = ['id' => 1, 'tstamp' => 123456789, 'alias' => '$array2'];
    $arrays = [$array1, $array2];
    
    $insert = 'INSERT INTO abcdef VALUES (?,?,?)';
    $insertStmt = $conn->prepare($insert);
    
    $bv_id      = NULL;
    $bv_tstamp  = NULL;
    $bv_alias   = NULL;
    $insertStmt->bind_param('iis', $bv_id, $bv_tstamp, $bv_alias);
    
    foreach ($arrays as $array) {
        // you could use extract($array, ...) below
        // but its use is highly discouraged
        $bv_id     = $array['id'];
        $bv_tstamp = $array['tstamp'];
        $bv_alias  = $array['alias'];
        $insertStmt->execute();
    }
    

    如果您必须使用数组,请使用以下方法:

    $array = ['id' => null, 'tstamp' => null, 'alias' => null];
    $insertStmt->bind_param('iis', $array['id'], $array['tstamp'], $array['alias']);
    foreach ($arrays as $copy) {
        foreach ($copy as $k => $v) {
            $array[$k] = $v;
        }
        $insertStmt->execute();
    }
    

    请注意,我在foreach 构造中为循环变量使用了不同的名称(我们需要跟踪绑定到语句的数组,并且循环变量在每次迭代时都会被覆盖)。您必须手动将循环变量中的值复制到绑定数组。

    【讨论】:

      【解决方案3】:

      你的情况

      此代码正在运行

      $insert = 'INSERT INTO abcdef VALUES (?,?,?)';
      $insertStmt = $conn->prepare($insert);
      foreach ($alias as $array) {
          $insertStmt->bind_param('iis', $array['id'], $array['tstamp'], $array['alias']);
          $insertStmt->execute();
      }
      

      因为对于数组迭代,我们使用 for 循环或 foreach 逐个键提取数组值,因此在此代码中,您的 $array 变量中的值将从 $alias 数组中一一设置

      在这段代码中

      $insert = 'INSERT INTO abcdef VALUES (?,?,?)';
      $insertStmt = $conn->prepare($insert);
      $insertStmt->bind_param('iis', $array['id'], $array['tstamp'], $array['alias']);
      foreach ($alias as $array) {
         $insertStmt->execute();
      }
      

      您使用了 $array 变量,该变量未在任何上部区域范围内初始化或声明,因此它将获得空值,因此每次执行函数都会获得空值......

      【讨论】:

      • 您不必初始化或声明要在 bind_param 中使用的变量。
      猜你喜欢
      • 1970-01-01
      • 2014-04-20
      • 2021-08-26
      • 2010-10-22
      • 2016-12-20
      • 2011-09-11
      • 2019-02-25
      相关资源
      最近更新 更多