在我看到的大多数SQL PHP准备语句的例子中,例如:
$sql = 'INSERT INTO tasks(task_name, start_date, completed_date) VALUES(:task_name, :start_date, :completed_date)';
$stmt = $this->pdo->prepare($sql);
$stmt->execute([
':task_name' => $taskName,
':start_date' => $startDate,
':completed_date' => $completedDate,
]);
字段名称几乎重复...四次!
- 在
INSERT INTO(...)
之后一次:task_name
(SQL中的列名) - 在
VALUES(...)
之后::task_name
- 一次在字典键中:
:task_name
- 一次在字典值中:
$taskName
(局部变量)
我知道这些都有不同的含义,但这种冗余真的很烦人:如果我们想改变查询中的某些内容,我们必须改变它4次!
如何在PHP中有一个更好的准备语句避免这么多冗余?
2条答案
按热度按时间x8diyxa71#
这是一个很好的问题,我有几个答案。
原始PHP
首先,您可以使用几种技巧来减少冗长,例如在查询中省略fields子句(并在values子句中为缺少的字段添加默认值)以及使用位置占位符:
我称之为技巧,因为它们并不总是适用的。
请注意,必须为表中的所有列提供一个值。它可以是一个简单的
null
值,或者,为了使它与省略的字段100%等效,您可以将它作为DEFAULT(field_name)
,以便它将插入表定义中定义的默认值。辅助函数
下一个层次是为插入创建一个辅助函数。当这样做时,必须敏锐地意识到SQL Injection through field names。
因此,这样的helper函数必须有自己的helper函数:
有了这样一个函数,我们可以创建一个助手函数,它接受一个表名和一个包含
field name => value
对的数据数组:我故意不使用命名的占位符,因为它使代码更短,占位符名称中可能不允许使用字符,但对于列名完全有效,例如空格或破折号;也是因为我们通常不关心它内部是如何工作的。
现在您的插入代码将变为
去掉了这么多重复
一个婴儿ORM
然而我也不喜欢上面的解决方案,其中有一些怪癖。
为了满足自动化的需要,我们可以实现面向对象编程这样一个伟大的概念。这样,您必须为每个表精确地编写一次列列表。
我专门写了一个complete working example来演示这个概念。
首先,您需要创建一个原型类,它将创建用于任何表的所有公共方法。像
之后,您将为特定的表创建实际的类,您将在其中提供表名和列列表:
然后-所有的魔法都在这里发生!- * 你根本不需要编写插入代码!* 相反,只需创建一个包含数据的数组,然后创建一个类的新示例,并调用该类的合适方法:
应该注意的是,现在可以使用mysqli或PDO,$db变量可以是任何一个。在将这个例子移植到mysqli时,只需要做一些小的调整
pqwbnv8z2#
这不是多余的,它是最不复杂的例子。
当您必须使用不同的参数多次执行一个查询时,预处理语句的重复性会发挥更大的作用。
下面的示例将按
value
获取从1到10的所有行:你也可以自由使用其他php逻辑来绑定参数: