将代码与数据库功能分开

时间:2008-11-13 03:33:51

标签: php database

我正在开发一个面向对象的PHP网站,我正在尝试确定从系统其他部分抽象数据库功能的最佳方法。现在,我有一个DB类来管理系统使用的所有连接和查询(它几乎是MDB2的接口)。但是,在使用这个系统时,我意识到我的代码中到处都有很多SQL查询字符串。例如,在我的User类中,我有类似的东西:

function checkLogin($email,$password,$remember=false){
    $password = $this->__encrypt($password);
    $query = "SELECT uid FROM Users WHERE email=? AND pw=?";

    $result = $this->db->q($query,array($email,$password));

    if(sizeof($result) == 1){
       $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
       $uid = $row['uid'];
    }else{
       return false;
    }

    /* Rest of the login script */
}

我想要做的是找出减少内联SQL数量的最佳方法。我知道这样做的一种方法是在User中为User使用的每个查询编写函数(如下所示),但这可能导致相当多的函数。

function checkLogin($email,$password,$remember=false){
    $password = $this->__encrypt($password);
    $uid = $this->do_verify_login_query($email,$password);

    /* Rest of the login script */
}

function do_verify_login_query($email,$encpw){
    $query = "SELECT uid FROM Users WHERE email=? AND pw=?";
    $result = $this->$db->q($query,array($email,$encpw));

    if(sizeof($result) == 1){
       $row = $result->fetchRow(MDB2_FETCHMODE_ASSOC);
       return $row['uid'];
    }else{
       return false;
    }
}

所以...我的问题。管理典型数据库应用程序将使用的大量查询的最佳技术是什么?我描述的方式是否是处理这种情况的正确方法?或者如何在DB类中注册查询列表并将每个传递给DB查询函数的唯一ID(例如USER_CHECKLOGIN)相关联?此方法也可以帮助提高安全性,因为它会限制可以仅运行到此列表中注册的查询,但在编写所有类函数时还要记住一件事。想法?

5 个答案:

答案 0 :(得分:7)

将SQL拉出到单独的函数中是一个不错的开始。您可以做的其他一些事情:

  • 为数据库访问代码创建单独的类。这将有助于确保您没有在所有PHP文件中散布SQL函数。
  • 从外部文件加载SQL。这完全区分了您的SQL代码和PHP代码,使其更易于维护。
  • 尽可能使用存储过程。这将完全从PHP代码中删除SQL,并通过降低外部SQL执行的风险来帮助提高数据库安全性。

答案 1 :(得分:4)

您可能希望了解如何实施ActiveRecord Pattern。使用诸如此类的设计模式可以为您处理表中的数据提供一些一致性。这些类型的方法可能存在一些缺点,主要是针对某些类型的查询的性能,但它可以解决。

答案 2 :(得分:4)

另一种选择可以是使用ORM,对于PHP来说最强大的是:

两者都允许您使用一组对象访问数据库,提供用于存储和查询数据的简单API,两者都有自己的查询语言,内部转换为目标DBMS本机SQL,这将简化从中迁移应用程序一个RDBMS到另一个具有简单配置更改。我还喜欢这样一个事实:你可以封装datamodel逻辑来添加验证,例如,只需扩展你的模型类。

答案 3 :(得分:3)

既然你说这是作为OO PHP做的,那你为什么首先将SQL分散在所有方法中呢?更常见的模型是:

  1. 使用ORM并让它处理数据库。
  2. 为您的类提供一个或多个'load'方法,这些方法使用单个查询将所有对象的数据提取到内存中,并使用单个查询来更新数据库中的所有内容。所有其他方法只需要进行内存操作,数据库交互仅限于加载/保存方法。
  3. 第一个选项通常会更强大,但第二个选项可能运行得更快,并且与您习惯做事的方式相比,可能会感觉更熟悉,如果其中任何一个都是关注的话。

    对于您的登录示例,我将采用的方式是简单地通过电子邮件地址加载用户,调用$user->check_password($entered_password),并抛出异常/返回false /如果check_password失败。 check_password或任何登录处理代码都不需要关心数据库,甚至知道数据库是用户加载的地方。

答案 4 :(得分:0)

另一种选择是将查询视为数据并将其存储在数据库中。例如,您可以创建一个存储具有名称的查询的表和另一个存储该查询的参数的表。然后在PHP中创建一个函数,它接受查询的名称和params数组并执行查询,返回任何结果。您还可以将其他元数据附加到查询以限制对特定用户的访问,将后期功能应用于结果等。