dongrong6235
2013-11-24 12:29
浏览 122
已采纳

在函数PHP中实例化类是不好的做法

I'm in the process of re factoring a lot of code to make it more testable and I have a bunch of useful functions that rely on an instantiated database object.

Things like this:

function id_from_name($table, $name)
{
    $db = get_database();
    //code that returns an id
}

function username_from_user_id($id)
{
    $db = get_database();
    //code that returns a username
}

There are a bunch more like id_exists, id_active etc.

Now I'm thinking that this isn't the right thing to do as the object should probably be passed through as an argument? But then that means creating and sending in a new object into each of these functions every time i want to use one.

So really, my questions are: Should I be moving these functions into their own class/library that has access to the database object? and are the examples that I've shown above generally a bad way of doing things?

图片转代码服务由CSDN问答提供 功能建议

我正在重新分解大量代码以使其更易于测试,我有一堆 依赖于实例化数据库对象的有用函数。

这样的事情:

  function id_from_name($ table,$ name)
  {
 $ db = get_database(); 
 //返回id的代码
 
 
函数username_from_user_id($ id)
 {
 $ db = get_database(); 
 //返回的代码 用户名
} 
   
 
 

有一些更像id_exists,id_active等。

现在我在想 这不是正确的事情,因为对象应该作为参数传递? 但这意味着每次我想使用一个新对象时,都会创建并发送新对象。

所以,我的问题是:我是否应该将这些函数移动到可以访问数据库对象的类/库中? 我上面所示的例子通常是一种糟糕的做事方式吗?

  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

4条回答 默认 最新

  • dongyongan9941 2013-11-24 12:37
    已采纳

    A better approach would be indeed to make classes. And you would be passing the database object to the constructor and make it an instance variable. That way every function would have access to the database object.

    Now the reason why it is considered bad to instantiate e.g. your database object in every function, is because if you decide for example one day to change your datasource, you might need a huge refactor. If you pass your database object into the constructor, you can just pass/inject the right object into the class without any refactor.

    ...a bit more about DI below...

    By passing your objects into the constructors, you also create a more clear API => you know which object depends on the other, you know exactly which class uses your DB object. If you start instantiating it or accessing it in a static way inside the functions like you did, I would have to look through all your classes to see where your DB object is used. One more point, dependency injection forces SRP (single responsibility principle) => if you start injecting too many objects (constructor gets many arguments), you should suspect your class is doing too much than what it should, and start refactoring.

    已采纳该答案
    打赏 评论
  • dtcmadj31951 2013-11-24 12:38

    You can create a class Table_Adapter and instantiate database object inside its constructor:

    class Table_Adapter 
    {
        protected $db;
    
        public function __construct() 
        {
            $db = get_database();
        }
    }
    

    Then you create a child class Items_Table_Adapter' that extendsTable_Adapterand put their all methods related toItems` table.

    class Items_Table_Adapter extends Table_Adapter
    {
        public function item_by_id($id)
        {
    
        }
    }
    

    Then you use it like:

    $tableAdapter = new Items_Table_Adapter();
    $item = $tableAdapter->item_by_id(1);
    
    打赏 评论
  • douyuai8994 2013-11-24 12:39

    Try something like:

    class YourClass{
    
        public static function get_database(){
            // your creation
            return $db;
        }
    
        public function id_from_name($table, $name)
        {
            /* your code */
            //code that returns an id
        }
    
        public function username_from_user_id($id)
        {
            /* your code */
        }
    
    }
    

    so you could just use it this way:

    $db = YourClass::get_database();
    $result = $db->id_from_name($table, $name);
    
    打赏 评论
  • douwu5009 2013-11-24 12:45

    It is certainly recommended that you have the option to swap out your database connection.

    Now, if your function get_database() looks like this:

    function get_database() {
      static $db;
      if (!$db)
        $db = new \mysqli(...);
      return $db;
    }
    

    Then you really, really should change it to a wrapper around a class, looking like this:

    function get_database_manager() {
      static $dbmgr;
      if (!$dbmgr)
        $dbmgr = new DbManager;
      return $dbmgr;
    }
    
    function get_database() {
      return get_database_manager()->getCurrentConnection();
    }
    

    where DbManager has an instance attribute with the current connection that is returned with getCurrentConnection(). If you want to swapt out the connection, do something like get_database_manager()->setConnection($newConn). Problem solved :)

    I'll leave the downsides of static programming here (it remains with many examples in this thread): http://kunststube.net/static/ as well as the common method to get rid of that (we have another approach here): http://en.wikipedia.org/wiki/Dependency_injection

    打赏 评论

相关推荐 更多相似问题