MVC,模型和数据访问对象

时间:2013-06-07 14:25:40

标签: php oop persistence

我有一个理论问题,我希望有人可以帮我解决。

我目前正在使用MVC设计模式在PHP中编写一个简单的Web应用程序。我已经看过并阅读了一些关于这个主题的教程,但它们通常要么过于复杂或过于简单。

所以我目前所拥有的是一个简单的User模型:

class User {

    private $username;
    private $group; //user, admin, etc

    // getters
}

我还有一个简单的Database类来实现这个类:

interface DatabaseInterface {

    public function connect();
    public function disconnect();
    public function prepare($sql = null);
    public function execute($params = array());
    public function rowCount();
    public function fetch();
}

我的问题是,如何将此Database课程与填充User课程相关联?

我目前所拥有的是另一个名为UserDAO的类,它在其构造函数中传递了Database类的引用,它有一个名为ValidateUser()的函数,然后使用上面的接口方法来检查用户对数据库。

class UserDAO {

    private $database;

    public function __construct($database) {

        $this->database = $database;
    }

    public function validateUser($username, $password) {

        $this->database->prepare('SELECT * FROM users WHERE...');
        ....
        return true/false;
    }
}

现在我通过构造函数将UserDAO对象传递到User类,并在ValidateUser()类中添加另一个User方法,基本上只调用ValidateUser()类中的UserDAO方法。

新的User类:

class User {

    private $username;
    private $group; //user, admin, etc
    private $userDAO;

    public function __construct($userDAO) {

        $this->userDAO = $userDAO;
    }

    public function validateUser($username, $password) {

        if($this->userDAO->validateUser($username, $password)) {

            // set stuff that i need
            return true;
        }

        return false;
    }

    // getters
}

关于这一点对我来说感觉不对。有人能帮我理解这个过程通常流动的方式吗?

此外,Database类通常是否保持静态,所以我可以使用Database::instance()之类的东西来呼叫连接?现在我正在PHP页面的开头创建一个数据库对象并传递它。

如果有任何不清楚的地方,请随时给我发表评论,我会尽快修复它。

感谢您对帖子的长度感到满意。

4 个答案:

答案 0 :(得分:3)

这取决于您的解决方案应该是最新的。

的Singleton

“最旧的”版本是在任何地方都有一个静态连接。您通过使用 singleton

来实现这一点
class database {

    private $instance = NULL;

    private function __construct()

    public function getDb() {
        return $this->instance?: $this->instance = new database();
    }

}

注册表

第二个更新的解决方案是使用注册表: 您可以拥有一个由所有其他类扩展的基类,并为

之类的调用提供方法
$this->getRegistry()->getDb

通常,注册表在脚本的开头填充,例如在引导程序中。 优点是您可以更好地对组件进行单元测试,因为没有静态部件,您可以为开发和生产环境定义不同的注册表...

依赖注入

依赖注入中的第三个“最新”和最佳方法。 通常你会有一些框架为你做这件事。我们的想法是,无论何时调用类的构造函数,所有依赖项(如数据库连接)都将由框架注入。

通过这种方式,您可以轻松定义“用户需要DB和Redis。商店需要DB,配置和FTP”...... 虽然这对于较小的项目来说是一个开销,但它对于大量且经过充分测试的项目有很大的帮助。

如果您曾经升级到多个数据库(例如一个主服务器和多个服务器),DI非常适合,因为您可以为代码的每个部分提供完成工作所需的数据库,无需更改任何一行代码。

答案 1 :(得分:1)

将数据库连接传递到UserDOA对象时,您正在创建依赖项。您的UserDOA对象现在依赖于数据库实例。

毫无疑问,管理这些依赖关系的最佳方式(不仅仅是使用您的UserDOA,而是使用其他DOA课程等)是通过 IoC (Inversion of Control)容器使用依赖注入

依赖注入允许您在容器中注册组件/类(以及创建类的对象实例所需的参数),然后将(在您的情况下)数据库实例注入到您指定的任何类中。这使代码更易于管理,可扩展,松散耦合并遵循SOLID principles

我建议看一个依赖注入容器是Symfony's dependency injection component,它已被提取并可单独使用。

答案 2 :(得分:0)

为了记录,对于一个商业项目来说,做一个贫血模型实际上是唯一的出路。

因此,我们不是创建具有多个成员/运算符/函数的膨胀模型(或域对象),而是只有一个模型,只有字段的定义,我们将服务分开。

a)模型类应该很简单,如果项目模型发生变化(例如,如果我们在数据库的表中添加一个新字段),它应该会发生变化。通常模型是实体(表的镜像)

b)dao类(其中一个服务)执行crud。作为一项服务,它可能是静态的(如果不是,它应该是),所以调用它应该是最简单的:

public function validateUser($username, $password) {

    if(UserDAO::validateUser($username, $password)) {

        // set stuff that i need
        return true;
    }

    return false;
}

但是,对于这种特定情况,函数validateUser与LOGIC(如果业务条件发生变化可能会更改的类)更相关。所以我们可以创建一个新的服务类来进行验证

class UserLogic {
    public static validateUser($user) {
        $userInDb=UserDao::getUser($user->idUser);
        // here goes the logic
        // why?, because it could changes, for example, validating the date, attempts, if its active...
        if ($userInDb!=null && $userInDb->password=$user->password) {
           return true;
        }
        return false;
    }
}

为了调用这个函数,我们使用了:

  $isValid=UserLogic::validateUser($someUser);

答案 3 :(得分:-1)

查看单身人士,例如$ this-> db = DB :: getInstance();

示例:

class Database { 
    // Store the single instance of Database 
    private static $instance; 

    private function __construct() { 
      // connection here
    } 

    public static function getInstance() { 
        if (!self::$instance) { 
            self::$instance = new Database(); 
        } 

        return self::$instance; 
    } 
}  

$db = new Database(); // the old way, don't do this.
$db = Database::getInstance(); // the singleton way - do this everywhere! it will always return the same object