【问题标题】:Mysqli abstraction, fetching arrays from prepared statementsMysqli 抽象,从准备好的语句中获取数组
【发布时间】:2010-12-24 17:32:14
【问题描述】:

最近我偶然发现了一个以前可以正常工作的库中的错误,如果我能弄清楚它在哪里,我会被诅咒的。

代码示例如下,对于其中的调试内容,我深表歉意,但我正在努力让它工作。

问题在于 $temp 是一个具有正确键(列名)但所有值都是 NULL 的数组。

我认为问题出在

call_user_func_array(array($query, 'bind_result'), $params);

有点,但我无法真正理解它。

public function fetchRows(){
    error_reporting(E_ALL+E_NOTICE);
    $args = func_get_args();
    $sql = array_shift($args);
    traceVar($sql, "Query");
    $colTypes = array_shift($args);
    if (!$query = $this->prepare($sql, $colTypes)) {
        die('Please check your sql statement : unable to prepare');
    }
    if (count($args)){
        traceVar($args,'Binding params with');
        call_user_func_array(array($query,'bindParam'), $args);
    }

    $query->execute();

    $meta = $query->result_metadata();
    while ($field = $meta->fetch_field()) {
        $params[] = &$row[$field->name];
    }
    traceVar($params,'Binding results with');
    call_user_func_array(array($query, 'bind_result'), $params);

    while ($query->fetch()) {
        traceVar($row,'After fetch');
        $temp = array();
        foreach($row as $key => $val) {
            $temp[$key] = $val;
        } 
        $result[] = $temp;
    }

    $meta->free();
    $query->close(); 
    //self::close_db_conn(); 
    return $result;
}

【问题讨论】:

    标签: php mysqli abstraction


    【解决方案1】:

    您提供的代码对我有用。

    call_user_func_array(...) 函数只是使用给定数组调用$query 对象上的bindParambind_result 方法,就好像您已将数组的每个元素作为方法参数提供一样。

    您可能希望使用以下代码检查您遇到问题的 SQL 语句。为了使其完全可测试,我对其进行了一些重写,因为原始代码依赖于抽象层中的语句类。

    <?php
    
    $db_host = 'localhost';
    $db_user = 'username';
    $db_pass = 'password';
    $db_name = 'database';
    
    $mysqli = new mysqli($db_host, $db_user, $db_pass, $db_name);
    
    print_r(fetchRows('SELECT something from some_table WHERE some_id = ?', 'i', 1));
    
    function traceVar($a, $b) {
        print_r(array($b => $a));
    }
    
    function fetchRows(){
            error_reporting(E_ALL+E_NOTICE);
            $args = func_get_args();
            $sql = array_shift($args);
            traceVar($sql, "Query");
    
            // Keep the column types for bind_param.
            // $colTypes = array_shift($args);
    
            // Column types were originally passed here as a second
            // argument, and stored in the statement object, I suppose.
            if (!$query = $GLOBALS['mysqli']->prepare($sql)){ //, $colTypes)) {
                    die('Please check your sql statement : unable to prepare');
            }
            if (count($args)){
                    traceVar($args,'Binding params with');
    
                    // Just a quick hack to pass references in order to
                    // avoid errors.
                    foreach ($args as &$v) {
                        $v = &$v;
                    }
    
                    // Replace the bindParam function of the original
                    // abstraction layer.
                    call_user_func_array(array($query,'bind_param'), $args); //'bindParam'), $args);
            }
    
            $query->execute();
    
            $meta = $query->result_metadata();
            while ($field = $meta->fetch_field()) {
                    $params[] = &$row[$field->name];
            }
            traceVar($params,'Binding results with');
            call_user_func_array(array($query, 'bind_result'), $params);
    
            while ($query->fetch()) {
                    traceVar($row,'After fetch');
                    $temp = array();
                    foreach($row as $key => $val) {
                            $temp[$key] = $val;
                    } 
                    $result[] = $temp;
            }
    
            $meta->free();
            $query->close(); 
            //self::close_db_conn(); 
            return $result;
    }
    

    【讨论】:

    • 我尝试了paste2.org/p/554177,它就像一个魅力,我想知道我的原始代码哪里出错了。
    • 在实现您的更改时我一定犯了一些错误,如果我将函数重写为 paste2.org/p/554194 然后我运行 paste2.org/p/554192 我仍然得到“Array ( [0] => Array ( [ID ] => [用户名] => [密码] => [名称] => [电子邮件] => [访问级别] => [IsTemp] => )"
    • 如果有任何用处,我还把课堂上的一些其他东西放在这里paste2.org/p/554201
    • 看来问题出在我在上一条评论中发布的其他方法上。我放置了一个 $db = $this->connection;在 if (!$query = $db->prepare($sql)) { 之前(因此使用原始对象而不是包装类)并且它可以工作。任何线索我可能做错了什么?
    • 查看您提供的其他代码,我注意到DBStatement::prepare(...),这可以解释为什么需要$db = $this-&gt;connection; 才能使其工作:-)。你能检查一下你原始代码中的DBStatement::prepare(...)方法是否也是空的吗?
    【解决方案2】:

    如果我们可以在启动时选择服务器,我们可以使用 php-mysqlnd 模块而不是 PHP 的 php-mysql 模块。 (或者你们中的一些人可能已经在使用它,运行“phpinfo();”并搜索“mysqlnd”):

    public function fetchRows(){
        ...
        $query->execute();
    
        $res = $query->get_result();
        while (($row = $res->fetch_assoc()))
            $result[] = $row;
        return $result;
        }
    }
    

    这对我来说似乎更简单。

    【讨论】:

    • 请问,您将用这些新知识回答多少问题?粗略估计就可以了
    • 两个。只是因为过去,我搜索了其中一些解决方案,但没有注意到有一个 get_result() 也可能有效。所以添加它以供将来用户参考。
    • 两个是相当数量的。尽管您要回答有关此事的所有数千个问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-11
    • 2014-06-25
    • 2012-12-01
    • 1970-01-01
    • 2011-05-28
    • 2013-07-19
    相关资源
    最近更新 更多