5

I'm hitting my head against a wall because the way I'm used to doing things in Perl doesn't work in PHP. This is most likely something so basic I don't know how to properly ask the question. The crux: I'm used to sending an array in list context as the argument to a function in Perl, but in PHP I'm only passing a reference to the array.

I'm trying to make a basic SQL query in PHP using MySQLi, for example, SELECT * FROM my_table WHERE first_name = 'Bob' AND last_name = 'Smith' AND city = 'Akron'. The trick is, my code doesn't know beforehand what terms will be in the query. The query is formed on the fly depending on what search terms the user wants to use. In Perl that's easy. In PHP I'm not sure what to do. Asked another way: how can I dynamically form and pass a list of values in PHP?

What I'm used to doing in Perl:

my %terms = (
    'first_name' => 'Bob',
    'last_name' => 'Smith',
    'city' => 'Akron'
);

my @keys = keys %terms;
my $where_string = join(' AND ', map("$_ = ?", @keys));
my @values = @terms{@keys};

my $sql = "SELECT * FROM my_table WHERE $where_string";
# Should give me 'SELECT * FROM my_table WHERE first_name = ? AND last_name = ? AND city = ?'
my $sth = $dbh->prepare($sql);
$sth->execute(@values);

What I'm trying to do in PHP that doesn't work:

foreach ($terms as $key => $value) {
    $keys[] = "$key = ?";
    $values[] = $value;
    $types .= (is_numeric($value) ? "i" : "s");
}
$where_string = implode(' AND ', $keys);
$sql = "SELECT * FROM my_table WHERE $where_string";
$sth = $dbh->prepare($sql);
$sth->bind_param($types, $values);  # Only I need to pass @values,
                                    #   the list of the elements of the array,
                                    #   not a reference to the array
$result = $sth->execute();

It could be my brain is so Perl-addled that I've forgotten all common sense.

3
  • always wandered why mysqli needs types while DBD::mysql can live without them. Commented Jan 15, 2014 at 20:46
  • Me too. This whole ordeal leaves me wondering why I'm using PHP at all. (Answer: so I know how to.) Commented Jan 15, 2014 at 21:19
  • I hope you are aware that your code is vulnerable to SQL injection and not as performant as possible. You can fix both by using placeholders and passing the variables to execute. Commented Jan 20, 2014 at 22:30

1 Answer 1

5

What you probably want is call_user_func_array():

$args = array_merge( array( $types ), $refs_to_values );
call_user_func_array( array( $sth, 'bind_param' ), $args );

Yes, it's kind of ugly; sometimes the flexibility of Perl is an advantage.

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

5 Comments

perhaps subclassing mysqli to hide ugliness.
Thanks! That eventually got me there. It took a slight bit more tweaking, since mysqli_stmt::bind_param expects, very specifically, a value and then a series of references. This worked:
$args[] = $types; for ($i = 0; $i < count($values); $i++) { $args[] = &$values[$i]; } call_user_func_array(array($sth, 'bind_param'), $args);
@LonelyPilgrim: Nice to see you got it working! Ps. If you want to post code in comments, wrap it in backticks ( ` ). It still won't look very good, but at least it's a little bit more readable.
Thanks. It's especially tricky posting code from an iPad! That will help next time.

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.