构建一个 OOP SQL 查询生成器

PHP 7实现了一种称为上下文相关的词法分析器。这意味着,如果上下文允许,通常保留的词可以被使用,因此,当构建面向对象的 SQL 构建器时,我们可以使用名为 and, or, not 等方法。

如何做…

1.我们定义了一个 Application/Database/Finder 类。在这个类中,我们定义了与我们最喜欢的SQL操作相匹配的方法。

  1. namespace Application\Database;
  2. class Finder
  3. {
  4. public static $sql = '';
  5. public static $instance = NULL;
  6. public static $prefix = '';
  7. public static $where = array();
  8. public static $control = ['', ''];
  9. // $a == name of table
  10. // $cols = column names
  11. public static function select($a, $cols = NULL)
  12. {
  13. self::$instance = new Finder();
  14. if ($cols) {
  15. self::$prefix = 'SELECT ' . $cols . ' FROM ' . $a;
  16. } else {
  17. self::$prefix = 'SELECT * FROM ' . $a;
  18. }
  19. return self::$instance;
  20. }
  21. public static function where($a = NULL)
  22. {
  23. self::$where[0] = ' WHERE ' . $a;
  24. return self::$instance;
  25. }
  26. public static function like($a, $b)
  27. {
  28. self::$where[] = trim($a . ' LIKE ' . $b);
  29. return self::$instance;
  30. }
  31. public static function and($a = NULL)
  32. {
  33. self::$where[] = trim('AND ' . $a);
  34. return self::$instance;
  35. }
  36. public static function or($a = NULL)
  37. {
  38. self::$where[] = trim('OR ' . $a);
  39. return self::$instance;
  40. }
  41. public static function in(array $a)
  42. {
  43. self::$where[] = 'IN ( ' . implode(',', $a) . ' )';
  44. return self::$instance;
  45. }
  46. public static function not($a = NULL)
  47. {
  48. self::$where[] = trim('NOT ' . $a);
  49. return self::$instance;
  50. }
  51. public static function limit($limit)
  52. {
  53. self::$control[0] = 'LIMIT ' . $limit;
  54. return self::$instance;
  55. }
  56. public static function offset($offset)
  57. {
  58. self::$control[1] = 'OFFSET ' . $offset;
  59. return self::$instance;
  60. }
  61. public static function getSql()
  62. {
  63. self::$sql = self::$prefix
  64. . implode(' ', self::$where)
  65. . ' '
  66. . self::$control[0]
  67. . ' '
  68. . self::$control[1];
  69. preg_replace('/ /', ' ', self::$sql);
  70. return trim(self::$sql);
  71. }
  72. }

2.每个用于生成SQL片段的函数都会返回相同的属性,即 $instance。这使得我们可以使用一个流畅的接口来表示代码,比如这样。

  1. $sql = Finder::select('project')->where('priority > 9') ... etc.

如何运行…

将前面定义的代码复制到 Application/Database 文件夹下的Finder.php文件中。然后您可以创建一个chap_05_oop_query_builder.php调用程序,它初始化了在第一章建立基础中定义的自动加载器。然后你可以运行Finder::select()来生成一个对象,从这个对象中可以呈现SQL字符串。

  1. <?php
  2. require __DIR__ . '/../Application/Autoload/Loader.php';
  3. Application\Autoload\Loader::init(__DIR__ . '/..');
  4. use Application\Database\Finder;
  5. $sql = Finder::select('project')
  6. ->where()
  7. ->like('name', '%secret%')
  8. ->and('priority > 9')
  9. ->or('code')->in(['4', '5', '7'])
  10. ->and()->not('created_at')
  11. ->limit(10)
  12. ->offset(20);
  13. echo Finder::getSql();

这是预编码的结果:

构建一个 OOP SQL 查询生成器 - 图1

参考

有关上下文相关词法分析器的更多信息,请参见本文:

https://wiki.php.net/rfc/context_sensitive_lexer