4

我有一个理论问题,希望有人能帮我弄清楚。

我目前正在使用 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中传递了类的引用,它有一个调用的函数,然后使用上面的接口方法来检查用户与数据库。DatabaseValidateUser()

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

4 回答 4

3

这取决于您的解决方案的最新程度。

辛格尔顿

“最旧”的版本是在任何地方都有一个静态连接。您可以通过使用单例来实现这一点:

class database {

    private $instance = NULL;

    private function __construct()

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

}

登记处

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

$this->getRegistry()->getDb

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

依赖注入

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

这样您就可以轻松定义“用户需要 DB 和 Redis。商店需要 DB、Config 和 FTP”……虽然这对于小型项目来说是一种开销,但对于大型且经过全面测试的项目来说却有很大帮助。

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

于 2013-06-07T15:09:29.120 回答
1

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

毫无疑问,管理这些依赖关系的最佳方法(不仅是使用您的 UserDOA,还使用您的其他 DOA 类等等)是通过使用依赖注入的IoC(控制反转)容器。

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

我推荐的一个依赖注入容器是Symfony 的依赖注入组件,它已经被提取出来并且可以单独使用。

于 2013-06-25T19:49:50.000 回答
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);
于 2016-03-26T21:15:37.333 回答
-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
于 2013-06-07T14:51:10.040 回答