Bind Param with array of parameters

2019-01-04 11:56发布

I have a function that does this:

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);
    }

Which sends off to my database class, which does this:

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

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

The problem is this doesn't work.

What I was hoping to do, was to take the $params list and have it list them after the $type, so that the query would resemble:

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

But obviously I'm going about it the wrong way.

is there a way to make the array...transform as it were, into a list to be printed out at the bind_param query stage?

标签: php mysqli bind
6条回答
何必那么认真
2楼-- · 2019-01-04 12:39

call_user_func_array()!

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

should do the job

UPDATE: you have also to change your params array:

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

as mysqli_stmt::bind_param expects the second and the following parameters by reference.


EDIT: Your query seems to be wrong. Maybe you have less fields than you have variables there. Do:

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

where you replace the name of the fields by the correct names

查看更多
Rolldiameter
3楼-- · 2019-01-04 12:44

It is important to note that mysqli_stmt_bind_param() requires parameters to be passed by reference, so the parameters for call_user_func_array() must be a reference. An example taken from class context:

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 );

}

}
查看更多
叼着烟拽天下
4楼-- · 2019-01-04 12:46

You get your error "Call to a member function bind_param() on a non-object" most likely, because your $this->mysqli->prepare encounters some kind of error. (see http://php.net/manual/de/mysqli.prepare.php - it returns FALSE on error, which seems to be the case here)

After you have resolved that problem, try this instead of your call of $stmt->bind_param:

call_user_func_array(array($stmt, 'bind_param'), array_merge($type, $params));
查看更多
老娘就宠你
5楼-- · 2019-01-04 12:47

Today, I did some research myself in order to create a shorter method of using the prepare statement. The answer @bwoebi is very helpful but not working for an unknown amount of parameters so this is an addition to his answer.

For instance:

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();
    }

using this thread: PHP: variable-length argument list by reference?

I managed to accomplish to pass on an unknown amount of parameters to the bind function inside the class. i then call upon the bind param function using call_user_func_array(...) with an array merge of the $type variable... (must be placed inside array for the merge)

Now i can call upon this function with $email and $password now being references:

$myClass->bind($query, "ss", $email, $password);
查看更多
Rolldiameter
6楼-- · 2019-01-04 12:49

As of PHP 5.6 you can utilize argument unpacking as an alternative to call_user_func_array, and is often 3 to 4 times faster.

<?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
?>

Taken from here.

So your code should look something like this:

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

            $this->query = $query;
            $stmt = $this->mysqli->prepare($this->query);
            $stmt->bind_param($type, ...$params);
            $stmt->execute;
        }
查看更多
看我几分像从前
7楼-- · 2019-01-04 12:49

The easiest way would be apparently switching from mysqli to PDO

It will let you to do it the way you want, and even without any additional functions:

function registerUser($firstName, $lastName, $address, $postcode, $email, $password)
{
    $sql  = "INSERT INTO Users VALUES (NULL, ?, ?, ?, ?, ?, ?)";
    $stmt = $this->db->prepare($sql);
    $stmt->execute(func_get_args());
}
查看更多
登录 后发表回答