【问题标题】:Dependency Injection for class with array of objects as class attribute以对象数组作为类属性的类的依赖注入
【发布时间】:2017-10-29 02:22:45
【问题描述】:

我是 php 中 OOP 编程的新手,并试图在我的 MVC 项目中理解和实现依赖注入功能。在下文中,我将解释一个超级简单的示例,说明我正在努力应用依赖注入的功能。实际的应用程序比这复杂得多,但是,这应该足以证明我遇到的问题。

我创建了一个名为“user”的模型,负责管理单个用户。类处理的数据(关于用户的数据)也保存在数据库表中。 “用户”类具有从数据库表加载和保存/更新数据的方法。可以使用从数据库加载的数据(通过使用用户 ID)或从提供给构造函数的数组加载来启动用户类。

该项目一次处理多个用户。因此,我创建了一个名为“users”的容器类。这个类有一个“用户”对象数组。但是,这个类也有方法从数据库中加载多个用户对象的数据(基于所有付费用户等标准),然后用数据创建对象数组。创建对象的数量取决于从数据库返回的用户数量。

以下是类的示例代码

class user
{
    private $data;  
    function __construct ($arData=””)
    {       
         $this->dbTable        ="user";
         if(!is_array($ar))
         {
              if($ar!="")
              {
                    $ar = $this->getDataFromDB($ar);
              }
              else
              {
                  $ar = array();
              }
        }
        $this->data = $ar;
    }

    function getDataFromDB($id_user){  … data base implementation … }
    ....
    Other methods
    ....
}

class users // the container class
{
    private $objUsers;
    function __ construct(){
        $this->objUsers = array();
    }

    function loadUsers($type){
        $userDataArray = $this->getUsersFromDatabase($type);

        foreach($useDataArray as $userData){
            $this->objUsers[] = new user($userData);
        }
    }
    function getUsersFromDatabase($userType) { …… database …… }
    …… other methods …..
}

我关心的是容器类(容器可能不是正确的说法)。我想知道创建这种类型的容器类的最佳实践以及对此的建议。此外,很明显这个容器类与“用户”类紧密耦合,不能单独测试。如何为这样的类实现依赖注入?

【问题讨论】:

  • 您将使users 更通用,并打破您与用户类中的数据库的任何紧密耦合。有几种方法可以做到这一点,但大多数都很难看,这真的取决于你是否打算将此容器用于其他任何用途。我有相反的情况,我从不直接调用user,而是创建用户并通过users类加载它们,该类返回user对象、用户对象数组或其他一些数据。
  • 所以我的一个快速示例不是去new User($data) 我做$Users->createUser($data) 并且用户与数据库没有连接,它只是一组定义/包装数据库表数据的属性。换句话说,用户只对数据负责,用户负责获取和创建一个用户或一组用户。如果这是有道理的。
  • 也就是说,我认为这不是依赖注入的好用例,主要原因是您通常不会拥有多种类型的用户,您可能具有权限级别等,但是用户始终是用户。没有太大的需要进行这种级别的分离,一些 PPL 可能不同意,但我不喜欢为了编码而编码。所以基本上做依赖注入,为了做它,当真的不需要的时候。鞋子合不合脚。
  • 感谢@ArtisticPhoenix。我喜欢你的方法。
  • 当然,请始终牢记给定类应该关注的内容。你可以限制的越多,你的代码就越容易维护和简单。

标签: php arrays oop dependency-injection containers


【解决方案1】:

正如我所说,我认为这不适合依赖注入。而且我不会为了说它使用依赖注入而这样设置它。

它不适合的主要原因是用户始终是用户。所以你总是在包装器、用户和用户之间有一个具体的合同。您可以指望用户具有某些方法。而且你没有添加到这些集合中的一些奇怪的第三类,它只是一个已知且定义明确的对象的集合。

也就是说,我会使用更多工厂风格的包装器,其中 User 是 2 个类中更简单的一个。 (注意,我没有测试任何这些,所以就像伪代码一样看它)

class users {

    public function createUser( array $data = []){

        if( $data['id'] ){
            $User = $this->getUser( $data['id'] );
            if( $User )
                return $User;  
        }
        //depending what you want you could search on other things
        //like the email, (unique)  and return the user.
        //you could make this as complex, or as simple as you want
        //it could simply create a new user, or check for an existing one first.

        return new User($data); //dependency
    }

    public function getUser( $id ){
        $stmt = $this->DB->prepare( "SELECT * FROM users WHERE id=:id" );
        $stmt->FetchMode(PDO::FETCH_CLASS, 'User');
        return $stmt->fetch(); //fetch right into the class
    }

    public function saveUser( User $User ){
        //I just added this to show how you can type hint the class
        // so that it only accepts Objects of the type User
    }

}

class user{

    protected $id;
    protected $username;
    protected $email;


    public function __construct(array $data = []){
        foreach( $data as $field=>$value){
            //this could be done better, with error checking etc.
            //but I just wanted to show how you can use the setters
            //dynamically when constructing with an array
            //this is useful because we are not hard coding the schema of User in any files
            //-note- PHP method calls are case insensitive.
            $this->set{$field} = $value;
        }
    }

    public function setId( $id ){ $this->id = $id; }

    public function getId(){ return $this->id; }

    public function setUsername( $username ){ $this->username = $username; }

    public function getUsername(){ $this->username; }

    public function setEmail( $email ){ $this->email = $email; }

    public function getEmail(){ return $this->email; }  
}

然后你可以担心像数据库这样的东西的依赖注入。这可以通过让用户构造函数接受 PDO 或数据库对象来表示。像这样

class Users{
     protected $DB;

     public function __construct( $DB ){
         $this->DB = $DB;
     }
}

Users 类不关心数据库凭据,甚至不关心您使用的特定数据库驱动程序。在某种程度上,它确实与基于 SQL 语法的驱动程序有一些耦合,这可能特定于特定的数据库。如果我们想让它成为一种“更真实”的依赖注入形式,我们应该使用像 Doctrine 这样的 ORM,或者某种查询构建器(而不是 PDO 本身)。然后我们的代码和数据库之间会有另一层抽象。

【讨论】:

  • 除了不扩展的形式之外,这基本上是我的想法,现在我完全清醒了,真的没有理由通过扩展来链接用户和用户。
【解决方案2】:

如果您需要用户访问用户并且他们不能分开扩展类。

class users {

}

class user extends users {

}

然后子用户可以访问父用户属性。

【讨论】:

  • 我会做相反的事情,让Users 成为工厂类,User 成为工厂生产的小部件更有意义。国际海事组织>
猜你喜欢
  • 2011-11-16
  • 1970-01-01
  • 2021-09-01
  • 1970-01-01
  • 2023-03-10
  • 2019-06-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多