【问题标题】:Is it bad practice to instantiate classes inside of functions PHP在函数 PHP 中实例化类是不好的做法吗
【发布时间】:2013-11-24 12:29:07
【问题描述】:

我正在重构大量代码以使其更具可测试性,并且我有许多依赖于实例化数据库对象的有用函数。

这样的事情:

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
}

还有很多类似 id_exists、id_active 等。

现在我认为这不是正确的做法,因为对象可能应该作为参数传递?但这意味着每次我想使用一个新对象并将其发送到每个函数中。

真的,我的问题是:我是否应该将这些函数移动到它们自己的可以访问数据库对象的类/库中?我上面展示的示例通常是一种不好的做事方式吗?

【问题讨论】:

标签: php function class


【解决方案1】:

更好的方法确实是制作课程。你会将数据库对象传递给构造函数并使其成为实例变量。这样每个函数都可以访问数据库对象。

现在实例化被认为是不好的原因,例如您在每个函数中的数据库对象,是因为如果您决定例如有一天更改您的数据源,您可能需要一个巨大的重构。如果您将数据库对象传递到构造函数中,您只需将正确的对象传递/注入到类中,而无需任何重构。

...更多关于 DI 的信息如下...

通过将对象传递给构造函数,您还可以创建一个更清晰的 API => 您知道哪个对象依赖于另一个对象,您确切知道哪个类使用您的 DB 对象。如果您开始实例化它或像您一样在函数内以静态方式访问它,我将不得不查看您的所有类以查看您的 DB 对象的使用位置。还有一点,依赖注入强制 SRP(单一责任原则)=> 如果您开始注入太多对象(构造函数获取许多参数),您应该怀疑您的类做的太多了,并开始重构。

【讨论】:

    【解决方案2】:

    您可以创建一个类Table_Adapter 并在其构造函数中实例化数据库对象:

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

    然后你创建一个子类Items_Table_Adapter' that extendsTable_Adapterand put their all methods related toItems`表。

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

    然后你像这样使用它:

    $tableAdapter = new Items_Table_Adapter();
    $item = $tableAdapter->item_by_id(1);
    

    【讨论】:

    • 如果不将$db 对象传递给get_database,它是如何工作的?
    【解决方案3】:

    尝试类似:

    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 */
        }
    
    }
    

    所以你可以这样使用它:

    $db = YourClass::get_database();
    $result = $db->id_from_name($table, $name);
    

    【讨论】:

      【解决方案4】:

      当然建议您可以选择更换数据库连接。

      现在,如果你的函数 get_database() 看起来像这样:

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

      那么你真的,真的应该把它改成一个类的包装器,看起来像这样:

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

      其中DbManager 具有与getCurrentConnection() 返回的当前连接的实例属性。如果您想更换连接,请执行get_database_manager()->setConnection($newConn) 之类的操作。问题解决了:)

      我将在这里留下静态编程的缺点(在这个线程中有很多例子):http://kunststube.net/static/ 以及摆脱它的常用方法(我们这里有另一种方法):http://en.wikipedia.org/wiki/Dependency_injection

      【讨论】:

        猜你喜欢
        • 2021-03-23
        • 2018-01-20
        • 2019-04-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-22
        • 2019-10-30
        相关资源
        最近更新 更多