web-dev-qa-db-fra.com

Bind Param avec un tableau de paramètres

J'ai une fonction qui fait ceci:

function registerUser($firstName, $lastName, $address, $postcode, $email, $password)
    {
        $params = array($firstName, $lastName, $address, $postcode, $email, $password);
        $result = $this->db->bind("INSERT INTO Users VALUES (?, ?, ?, ?, ?, ?)", 'ssssss', $params);
    }

Ce qui envoie à ma classe de base de données, qui fait ceci:

public function bind($query, $type, $params)
        {

            $this->query = $query;
            $stmt = $this->mysqli->prepare($this->query);
            $stmt->bind_param($type, $param);
            $stmt->execute;
        }

Le problème est que cela ne fonctionne pas.

Ce que j'espérais faire était de prendre la liste $params et de la lister après le $type, afin que la requête ressemble à ceci:

$stmt->bind_param('ssssss', $firstName, $lastName, $address, $postcode, $email, $password);

Mais évidemment, je m'y prends mal.

existe-t-il un moyen de transformer le tableau ... en quelque sorte en une liste à imprimer au stade de la requête bind_param?

20
David G

call_user_func_array()!

call_user_func_array(array($stmt, "bind_param"), array_merge(array($type), $params));

devrait faire le travail

UPDATE: vous devez aussi changer votre tableau params:

$params = array(&$firstName, &$lastName, &$address, &$postcode, &$email, &$password);

comme mysqli_stmt::bind_param attend le deuxième et les paramètres suivants par référence.


EDIT: Votre requête semble être fausse. Peut-être que vous avez moins de champs que de variables. Faire:

"INSERT INTO Users (field1, field2, field3, field4, field5, field6) VALUES (?, ?, ?, ?, ?, ?)"

où vous remplacez le nom des champs par les noms corrects

26
bwoebi

À partir de PHP 5.6, vous pouvez utiliser la décompression d'arguments comme alternative à call_user_func_array, et est souvent 3 à 4 fois plus rapide.

<?php
function foo ($a, $b) {
     return $a + $b;
}

$func = 'foo';
$values = array(1, 2);
call_user_func_array($func, $values);
//returns 3

$func(...$values);
//returns 3
?>

Tiré de ici .

Donc, votre code devrait ressembler à quelque chose comme ça:

public function bind($query, $type, $params)
        {

            $this->query = $query;
            $stmt = $this->mysqli->prepare($this->query);
            $stmt->bind_param($type, ...$params);
            $stmt->execute;
        }
9
Havardox

Vous obtenez probablement l'erreur "Appel à une fonction membre bind_param () sur un non-objet", car votre $ this-> mysqli-> prepare rencontre une sorte d'erreur . (Voir http: // php.net/manual/de/mysqli.prepare.php - il retourne FALSE en cas d'erreur, ce qui semble être le cas ici)

Après avoir résolu ce problème, essayez ceci à la place de votre appel de $ stmt-> bind_param:

call_user_func_array(array($stmt, 'bind_param'), array_merge($type, $params));
2
phry

Aujourd'hui, j'ai moi-même effectué des recherches afin de créer une méthode plus courte d'utilisation de la déclaration prepare. La réponse @bwoebi est très utile mais ne fonctionne pas pour une quantité inconnue de paramètres, c’est donc un ajout à sa réponse. 

Par exemple:

public function bind($query, $type, &...$params)
    {

        $this->query = $query;
        $stmt = $this->mysqli->prepare($this->query);
        call_user_func_array(array($stmt, "bind_param"), array_merge([$type], $params));
        $stmt->execute();
    }

en utilisant ce fil: PHP: argument de longueur variable liste par référence?

J'ai réussi à transmettre une quantité inconnue de paramètres à la fonction bind de la classe. i appelle ensuite la fonction bind param en utilisant call_user_func_array (...) avec une fusion de tableau de la variable $ type ... (doit être placée dans un tableau pour la fusion)

Maintenant, je peux faire appel à cette fonction avec $ email et $ mot de passe étant maintenant des références:

$myClass->bind($query, "ss", $email, $password);
1
Mart

Le moyen easiest serait apparemment de passer de mysqli à PDO

Il vous permettra de le faire comme vous le souhaitez, et même sans fonctions supplémentaires:

function registerUser($firstName, $lastName, $address, $postcode, $email, $password)
{
    $sql  = "INSERT INTO Users VALUES (NULL, ?, ?, ?, ?, ?, ?)";
    $stmt = $this->db->prepare($sql);
    $stmt->execute(func_get_args());
}
1
Your Common Sense

Il est important de noter que mysqli_stmt_bind_param() requiert que les paramètres soient transmis par référence. Les paramètres de call_user_func_array() doivent donc être une référence. Un exemple tiré du contexte de la classe:

function execute( string $query, string $type, array $params )
{
    if ( !$stmt = $this->mysqli->prepare( $query ) ) 
        throw new \Exception( 'Prepare failed: ' . $query . PHP_EOL . $this->mysqli->error );

    // call stmt->bind_param() with variables to bind passed as a reference 
    call_user_func_array( 
        array( $stmt, 'bind_param' ), 
        array_merge( 
            array( $type ), 
            array_map( function( &$item ) { return $item; }, $params ) 
        ) 
    );

    if ( !$stmt->execute() ) 
        throw new \Exception( 'Execute failed: ' . PHP_EOL . $stmt->error );

}

}
0
Danijel