Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/drupal/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP:mysqli_stmt->;close()影响stmt的早期副本_Php_Mysqli - Fatal编程技术网

PHP:mysqli_stmt->;close()影响stmt的早期副本

PHP:mysqli_stmt->;close()影响stmt的早期副本,php,mysqli,Php,Mysqli,我正在制作一个函数,以便在sql查询中更轻松地使用准备好的语句。但是在工作中,我遇到了一个奇怪的错误。 当您在$response的第一个var_dump下面运行代码时,会像我期望的那样打印$stmt变量,但在关闭$stmt后,它会发出大量警告并打印一个填充为空的$stmt版本。我只将$stmt复制为$response,因此我不希望在关闭$stmt时更改$response。 有人能解释一下为什么会发生这种情况,以及我如何预防它吗 function sql_bug() { global $d

我正在制作一个函数,以便在sql查询中更轻松地使用准备好的语句。但是在工作中,我遇到了一个奇怪的错误。 当您在
$response
的第一个
var_dump
下面运行代码时,会像我期望的那样打印
$stmt
变量,但在关闭
$stmt
后,它会发出大量警告并打印一个填充为空的
$stmt
版本。我只将$stmt复制为
$response
,因此我不希望在关闭
$stmt
时更改
$response
。 有人能解释一下为什么会发生这种情况,以及我如何预防它吗

function sql_bug() {
    global $dbc; // Database connection
    $sql = "UPDATE users SET username = 'J0R1AN' WHERE id = 1"; // Test query
    if ($stmt = $dbc->prepare($sql)) {
        if ($stmt->execute()) {
            $response = $stmt->get_result();
            if ($response === false) {
                // Checks for e.g. UPDATE queries that return bool(false) instead of a mysqli_result, 
                // and sets $response to $stmt instead, to return more valuable information when using UPDATE
                $response = $stmt;
            }
            var_dump($response); // Prints expected $stmt variable
            $stmt->close(); // Somehow changes $response?
            var_dump($response); // Prints $stmt variable filled with NULLS
            return $response;
        }
    }
    return false;
}

变量赋值不会在PHP中创建对象的新副本。要创建副本,您需要使用
clone
。简单的例子:

$obj  = (object) ['a'=>42];
$new_obj = $obj;
$obj->a = 100;

var_dump($new_obj); 
// outputs 
// stdClass Object
// (
//     [a] => 100
// )
你已经成为多个谬误的受害者

  • 您不需要关闭任何内容。PHP将为您做这件事。使用
    close
    只会使很多事情复杂化
  • 不要检查
    prepare
    execute
    函数的返回值。而是启用mysqli错误报告
  • 不要使用全局对象或将其使用限制到绝对最小值
  • 您不需要公开函数外部的
    mysqli\u stmt
    mysqli\u result
    对象。执行语句并获取数据后,可以放弃它们
  • 如果我们想正确修复此功能,可以执行以下操作:

    function sql_bug(\mysqli $dbc, string $sql, array $params = []): ?array {
        $stmt = $dbc->prepare($sql);
        if ($params) {
            // bind optional parameters if the query has variable input
            $stmt->bind_param(str_repeat("s", count($params)), ...$params);
        }
        $stmt->execute();
        $response = $stmt->get_result();
        if ($response) {
            // If the query returned results then fetch them into an array and return it
            return $response->fetch_all(MYSQLI_BOTH);
        }
        // return nothing if the query was successfully executed and it didn't produce results
        return null;
    }
    

    上述函数是一个通用函数,可以处理任何带参数和不带参数的SQL语句。如果查询是INSERT或UPDATE,它将不返回任何内容;如果查询是SELECT,它将返回数组中的数据。无需复制或返回内部对象。您正在编写一个函数来从mysqli内部进行抽象。

    您需要停止手动检查错误。请阅读:如果你关闭了这个物体,你希望发生什么?为什么要关闭它?“我只将$stmt复制为$response”-不,对象不会以这种方式复制。您需要使用
    clone
    来复制对象。很抱歉,我没有澄清,我关闭了该语句,因为我读到这是一个很好的做法,并让MySQL知道它可能会忘记该语句。我希望$response变量(当它仍然有内容时是$stmt的副本)保持不变,这样我可以在关闭原始$stmtOh后返回它并使用变量,我只说下一个注释,所以如果在对象上使用
    =
    操作符,它不会复制它?谢谢编辑:当我在
    $stmt
    变量上运行
    clone
    时,我得到以下错误:
    致命错误:未捕获错误:尝试克隆mysqli\u stmt类的不可克隆对象
    。我需要做些什么才能让它“可克隆”吗?谢谢你的评论,我从中学到了很多。但我希望函数具有的一个特性是返回$stmt变量,这样我就可以读取更新查询中受影响的_行。我会稍微修改一下你的代码,这样就不需要了。它也是mysqli对象的一个属性。请看一件事,当我执行sql查询,例如UPDATE,然后在
    sql\u bug()
    函数本身
    echo$dbc->infected\u rows
    时,我得到了预期的超过0个infected\u rows,但当我在函数外部执行相同的代码时,因此在调用
    sql\u bug()
    后,我总是得到-1作为infected\u rows。在文档中,它说它将从上一个查询返回,但感觉好像我遇到了一些范围问题。我也没有给出错误,因为
    error
    变量是空的,我的更新查询按预期工作,并且实际更改了values@J0R1AN请你把这个问题单独问一下好吗。使用此函数创建一个简单的可复制示例。