11

A veces hay consultas que traen varias columnas y resulta tedioso tener que vincular el resultado de cada columna a una variable. En esos casos uno podría preferir almacenar el conjunto de resultados en un arreglo usando por ejemplo el método fetch_assoc.

Con una consulta obtenida mediante query, (consultas no preparadas), no hay ningún problema. Pero cuando se trata de consultas preparadas mysqli hace las cosas verdaderamente difíciles y no entiendo por qué.

Investigando, creí dar con la solución... El Manual de PHP describe el método get_result, como el mejor camino para obtener un conjunto de resultados proveniente de una consulta preparada dentro de un array asociativo.

Peeeero esta nota del Manual hace que tu relación con mysqli sea irreconciliable:

Disponible sólo con mysqlnd.

mysqlnd no viene instalado en todos los sistemas... y dicha limitación no es válida cuando intentas dar alguna respuesta a dudas planteadas aquí.

La pregunta

¿Cómo almacenar un conjunto de resultados en un array asociativo en mysqli usando consultas preparadas si no tenemos mysqlnd instalado?

En este código yo implementé una función mi_fetchassoc que hace el trabajo, pero no es lo ideal... también en ella debo especificar cada vez cómo se llaman las columnas.

function mi_fetchassoc($stmt)
{
    if($stmt->num_rows>0)
    {
        $rs = array();
        $md = $stmt->result_metadata();
        $params = array();
        while($field = $md->fetch_field()) {
            $params[] = &$rs[$field->name];
        }
        call_user_func_array(array($stmt, 'bind_result'), $params);
        if($stmt->fetch())
            return $rs;
    }

    return null;
}
A. Cedano
  • 86,578
  • 19
  • 122
  • 221

2 Answers2

11

Encontré esta respuesta en SO, con unos ejemplos interesantes, quizás te puede servir.

Ejemplo:

Aquí hay una solución más ordenada basada en el mismo principio:

function Arreglo_Get_Result( $Statement ) {
    $RESULT = array();
    $Statement->store_result();
    for ( $i = 0; $i < $Statement->num_rows; $i++ ) {
        $Metadata = $Statement->result_metadata();
        $PARAMS = array();
        while ( $Field = $Metadata->fetch_field() ) {
            $PARAMS[] = &$RESULT[ $i ][ $Field->name ];
        }
        call_user_func_array( array( $Statement, 'bind_result' ), $PARAMS );
        $Statement->fetch();
    }
    return $RESULT;
}

Nota: se podría incorporar a una clase utilitaria, para poder usarla desde cualquier parte del programa.


Normalmente sin mysqInd harías:

$sql = "SELECT * FROM books WHERE ean = ?"; 
$id=4;

//Preparar la consulta
$stmt=$mysqli->prepare($sql);

//Evaluar si  tuvo  éxito
if ($stmt) {        
    $stmt->bind_param("i", $id);
    $stmt->execute();

    $Resultado = get_result($stmt);        
    while ($row = array_shift($Resultado)) {
        # trabajos con los datos
    }

}

Normalmente con mysqInd harías:

$sql = "SELECT * FROM books WHERE ean = ?"; 
$id=4;

//Preparar la consulta
$stmt=$mysqli->prepare($sql);

//Evaluar si  tuvo  éxito
if ($stmt) {        
    $stmt->bind_param("i", $id);
    $stmt->execute();

    $Resultado = $stmt->get_result();
    while ($row = $Resultado->fetch_array()) {
        # trabajos con los datos
    }

}

Nota: el uso y la sintaxis son casi idénticos. La diferencia principal es que la función de reemplazo devuelve una matriz de resultados, en lugar de un objeto de resultado.

@A.Cedano lo ha probado y funciona perfectamente, aquí puedes ver una respuesta por el más completa (¿Cómo aseguro mi conexión de PHP a MySQL?).

Diablo
  • 6,417
  • 2
  • 21
  • 40
  • Pero está usando `get_result` en el primer caso y el problema es que sin mysqlnd instalado esa función no funciona. – A. Cedano Nov 01 '17 at 22:56
  • @A.Cedano te he puesto el ejemplo completo de **SO**. – Diablo Nov 01 '17 at 23:10
  • Probado y funciona... y ya la he usado en una respuesta [aquí](https://es.stackoverflow.com/a/114182/29967). Me he encontrado con varias situaciones como esta en la que se quiere un conjunto de resultados asociativo y se recurre a manipulaciones complicadas para obtenerlo. No entiendo por qué mysqli no ha implementado un método con `FETCHASSOC` de PDO para el mismo `mysqli` sin tener que pasar por `mysqlnd` – A. Cedano Nov 02 '17 at 09:41
  • @A.Cedano me alegro que funciono, yo tampoco entiendo porque no han creado una función para dicho problema, parecido a `PDO` como has comentado. Un saludo. – Diablo Nov 02 '17 at 10:32
  • Esta función es una maravilla. Yo la estoy usando en algunas respuestas sobre preguntas que implican obtener el conjunto de resultados en un arreglo asociativo con consultas preparadas. Te quiero sugerir algunas cosas: 1. Que quites el *personalmente no lo he probado*, genera desconfianza en el lector... yo lo he probado y funciona; 2. que pongas una nota en la respuesta de que se podría incorporar a una clase utilitaria, para poder usarla desde cualquier parte del programa; 3. de paso le pondría un nombre distinto a la función propia de `mysqlnd`. Gracias de nuevo. – A. Cedano Jan 19 '18 at 20:32
  • @A.Cedano de nada, un placer verte ayudado, ya he modificado mi respuesta, vi también tu respuesta hoy, y la he añadido al final, ya que es un ejemplo más completo, y podrá servir a otro usuario como debe implementarlo correctamente. Un saludo – Diablo Jan 19 '18 at 21:17
  • Pásense a PDO y OpPa y listo que les cuesta establecer una clase que se encargue de recibir el Statenent, el arrays de variables se la consulta y pasarle el parámetro de organización de dato... Hay páginas como php clases donde ya hay librería genéricas para manejar todos estos datos y consultas. – ArcanisGK507 Jan 25 '18 at 04:07
2

Una otra alternativa, en caso de recibir datos por medio de PHP json_decode

Es consultar los elementos de la matriz directamente en bind_result(), en lugar de usar variables separadas.

$member = array();
$stmt->bind_result($member['id'], $member['firstName'], $member['lastName'], $member['email']);

Y obtenemos resultados deseados por medio de json_decode

while ($stmt->fetch()) {
    echo json_encode($member);
}
Publisere.com
  • 2,384
  • 5
  • 14