22

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?

1
  • 1
    Your query is apparently wrong. Do before the bind_param one var_dump($this->mysqli->error); to know what's going wrong. Commented Apr 26, 2013 at 12:33

7 Answers 7

28

call_user_func_array "Call a callback with an array of parameters"

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

Sign up to request clarification or add additional context in comments.

6 Comments

You were right - there was a missing field. I have fixed this However upon using call_user_func_array as above, I get the error "Warning: array_merge() [function.array-merge]: Argument #1 is not an array Warning: call_user_func_array() expects parameter 2 to be array, null given"
@DavidG Use then array_merge(array($type), $params). But when your $params is not set, I cannot do anything as it should be right.
Thank you for your help :) It almost works. I get an error: Warning: Parameter 2 to mysqli_stmt::bind_param() expected to be a reference, value given So I will try to work out what that is about
@DavidG humm, seems as if you'd need to do some eval() here... all parameters except the first are by reference (and I don't know why...)
@DavidG: see this question to learn about your error message. And please don't just put @s before your statements, it will just suppress error messages, not repair the causes of them.
|
15

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

Comments

2

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

Comments

2

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

4 Comments

@Your Common Sense do you consider PDO better over mysqli? I also use mysqli mostly, but don't know much about PDO.
@Aris as you can see, PDO require dramatically less code. These 2 lines is all you need. No extra bind function required. PDO can do it out of box
sounds great. I will try to use in the future. And I realize it's a native php functionality?
@Aris yes, that's the point. And also PDO has error reporting too, so, you don't need to check for the errors manually. and there are many other things liker getting a scalar right out of query and many more things makes your code better and readable
0

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

}

}

Comments

0

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

Comments

0

Not beautiful, but thats what I use.

function _BindParam(&$stmt, &$values){
    $types="";
    foreach($values as $val){
      if(is_string($val)){$types.="s";continue;}
      if(is_int($val)){$types.="i";continue;}
      if(is_float($val) || is_double($val)){$types.="d";continue;}
      throw new Exception('Invalid value type');
    }
   $stmt->bind_param($types,...$values);
}

1 Comment

Don't know why this was downvoted. It worked beautifully for me.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.