如何在PHP中传递一个值列表(类似于Perl),而不是引用数组?

5

我正在为一个问题苦苦挣扎,因为我习惯在Perl中处理事情的方式在PHP中不起作用。这很可能是一些非常基本的东西,我不知道如何正确地提问。关键点:在Perl中,我习惯将数组作为列表上下文中的参数发送到函数中,但在PHP中,我只传递了对数组的引用。

我正在尝试使用MySQLi在PHP中进行基本的SQL查询,例如SELECT * FROM my_table WHERE first_name = 'Bob' AND last_name = 'Smith' AND city = 'Akron'。问题是,我的代码无法预先知道查询中会有哪些条件。查询根据用户想要使用的搜索条件动态形成。在Perl中很容易实现,但在PHP中我不确定该怎么做。换句话说:如何在PHP中动态形成并传递值列表?

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

我正在尝试使用PHP实现的功能:

但无法正常工作。
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();

也许是因为我的大脑被Perl日用成了马蜂窝,以至于我忘记了常识。


我一直想知道为什么mysqli需要类型,而DBD::mysql却可以不需要它们。 - mpapec
我也是。整个经历让我想知道为什么我使用PHP。(答案:因为我知道如何使用它。) - Joseph T. Richardson
希望您知道,您的代码容易受到SQL注入攻击,并且性能不够优秀。您可以通过使用占位符并传递变量来执行来解决这两个问题。 - Alexander Hartmaier
1个回答

5
您可能需要的是 call_user_func_array() 函数:
$args = array_merge( array( $types ), $refs_to_values );
call_user_func_array( array( $sth, 'bind_param' ), $args );

是的,它有点丑陋;有时候Perl的灵活性是一个优点。


或许可以通过继承mysqli来隐藏丑陋的细节。 - mpapec
谢谢!最终让我成功了。需要稍微调整一下,因为mysqli_stmt :: bind_param非常明确地期望一个值,然后是一系列的引用。这个方法可行: - Joseph T. Richardson
$args[] = $types; for ($i = 0; $i < count($values); $i++) { $args[] = &$values[$i]; }call_user_func_array(array($sth, 'bind_param'), $args); - Joseph T. Richardson
@LonelyPilgrim:很高兴看到你解决了问题!顺便说一句,如果你想在评论中发布代码,请用反引号(`)将其包裹起来。虽然显示效果可能不太好,但至少会更易读一些。 - Ilmari Karonen
谢谢。从iPad发布代码特别棘手!下次这会有帮助。 - Joseph T. Richardson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接