我对PDO准备的语句相对陌生。
我忍不住觉得,必须有一种更简单、更整洁的方法来完成以下操作:无论如何,我都要将所有内容加载到一个数组中,然后必须将整个内容重写为一组':blah'=>$find['blah']废话。
做下面的事情有什么更整洁的方法?
$stmt = $db->prepare("UPDATE googleplay SET name=:name, releasedate=:releasedate, version=:version, image=:image, url=:url, rating=:rating WHERE id=:id");
$stmt->execute(array(
':id'=>$found['id'],
':name'=>$found['name'],
':releasedate'=>$found['releasedate'],
':version'=>$found['version'],
':image'=>$found['image'],
':url'=>$found['url'],
':rating'=>$found['rating']
));
您不需要在密钥名称前加上:
,不加也可以。因此:
$stmt->execute($found);
即使你必须这样做,也要自动完成:
$found = array_combine(array_map(function ($key) { return ":$key"; }, array_keys($found)), $found);
在PDO文档中还有其他方法可以做到这一点,有些更整洁,有些则不然。您可以编写一个php函数来完成这项工作,使其更加整洁。
同样的函数也允许使用?
来表示目标。对于许多一次性查询,它更干净。
不过,最简洁的是使用ORM(对象关系映射器),如Doctrine或任何数量的ActiveRecord克隆(如Laravel)。
$allowed = array('name', 'releasedate', 'version', 'image', 'url', 'rating');
$sql = "UPDATE users SET ".pdoSet($allowed, $values, $found)." WHERE id = :id";
$stm = $dbh->prepare($sql);
$values["id"] = $found['id'];
$stm->execute($values);
其中pdoSet()
是从提供的数组中产生SET语句的函数(根据允许的字段列表检查输入数组)
然而,最好的方法是实现另一种类型的占位符,这将使您的代码在世界上最整洁:
$db->query("UPDATE users SET ?u WHERE id = ?i", $found, $id);
假设CCD_ 4已经被验证(意味着不是来自用户输入而是硬编码或过滤掉)并且CCD_ 5不是数组的一部分。
// a closure that, given a key, returns a SET subclause for an UPDATE statement
$cl_set = function($k) {
if (!preg_match('/^[[:alnum:]_]+$/', $k))
throw new Exception('Key cannot be used as a placeholder name');
return "$k = :$k";
};
// use our closure to generate the SQL
$stmt = $db->prepare(
'UPDATE googleplay SET ' . implode(', ', array_map($cl_set, array_keys($found)))
);
// execute - this works because of the observation in @deceze's answer:
$stmt->execute($found);