views:

390

answers:

1

Lately I've stumbled upon an error in a lib that used to work just fine, and I'll be damned if I can figure out where it is.

The code sample is below, and I apologize for the debug stuff that's inside it, but I'm trying to get it to work.

The problem is that $temp is an array with correct key (the name of the columns) but all the values are NULL.

I think the problem lies in the

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

bit, but can't really wrap my head around it.

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;
}
A: 

The code you provided works for me.

The call_user_func_array(...) function just calls the bindParam or bind_result methods on the $query object with the given array, as if you had provided each element of the array as a method argument.

You may want to check the SQL statement you are having the problem with, with the code below. I've rewritten it a bit in order to make it fully testable, since the original code depends on the statement class in your abstraction layer.

<?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;
}
Inshallah
I tried with http://paste2.org/p/554177 and it works like a charm, I wonder where my original code is breaking.
Madness
I must be making some mistake when implementing your changes, if I rewrite the function as http://paste2.org/p/554194 and then I run http://paste2.org/p/554192 I still get "Array ( [0] => Array ( [ID] => [Username] => [Password] => [Name] => [Email] => [AccessLevel] => [IsTemp] => ) )"
Madness
If it is of any use, I also placed some other bits from the class here http://paste2.org/p/554201
Madness
It would appear that the problem is with the other methods I posted in my last comment. I placed a $db = $this->connection;before if (!$query = $db->prepare($sql)) { (thus using the original object and not the wrapper class) and it works.Any clue of what I might be doing wrong?
Madness
Looking at the other code you provided, I notice that `DBStatement::prepare(...)` is **empty**, which would explain why `$db = $this->connection;` is required to make it work :-). Can you check whether the `DBStatement::prepare(...)` method in your original code is empty too?
Inshallah
Yes it is, but after all I don't use it. I use Database::prepare, so it shouldn't matter.
Madness
Ah yes, the empty method was a bit confusing. I actually tried it now and it gives an error about `'bind_param'` expecting a reference. In `DBStatement::bindParam` add the reference operator to the `$params` argument: `call_user_func_array(array($this->baseObject, 'bind_param'), `.
Inshallah
Tried making some changes but I still get an empty set of values.http://paste2.org/p/555802 is the updated version.I wonder if it has something to do with the use of func_get_args breaking the reference.
Madness
This is weird. It work for me with PHP 5.3.0. What's the output of `php -v`? You can try adding the reference operator in both `DBStatement::__call` and `Database::__call`.
Inshallah