【问题标题】:PHP Mysqli Connection Through Multiple ClassesPHP Mysqli通过多个类连接
【发布时间】:2014-11-08 07:56:57
【问题描述】:

所以,我对 PHP 很老了,但大多数时候我使用的是过程式风格。我一直试图遵循 MVC 模式,即使我是在程序上做事。另外,我习惯了一些框架,比如 CakePHP 和 CodeIgniter。但是,我还没有使用 OOP 从头开始​​做任何事情。今天我这样做是为了大学工作,我有几个问题。

通常,在框架中,我们只需在任何控制器类上执行$this->database->query(),它就可以工作。在程序上,数据库的$link 进入全局范围,因此您不必担心。我一直在寻找一种方法来对我的代码中的每个类都做到这一点,但没有成功。我能得到的最好的结果是使用 Singleton 类来实例化数据库,但是,我需要在每个类中检索数据库链接。因此,例如,在 Users 类中,我必须在构造函数、Main 类以及其他所有类中获取它。

我的问题很简单。如何通过多个类使用数据库连接链接,而不必在所有类中实例化数据库。 而且,如果这样做是最好的更简单的方法,除了 Singleton 方法还有其他方法吗?

顺便说一下,我正在使用 Mysqli 库。

这是我一直在使用的课程。

class DB extends Mysqli {
    protected static $instance;

    private function __construct() {
        global $config;

        parent::__construct($config['db']['host'], $config['db']['user'], $config['db']['password'], $config['db']['database']);

        if($this->connect_error)
            die('Connect Error ('. $mysqli->connect_errno .') '. $mysqli->connect_error);
    }

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

这是一个类使用示例。

class Main {
    protected $db;

    public function __construct() {
        $this->db = DB::getInstance(); // <-- having to do that in every class is the problem
    }

    protected function start() {
        $this->db->query(something...); // works
    }
}

【问题讨论】:

    标签: php database class mysqli singleton


    【解决方案1】:

    更好的方法是使用dependency injection,而不是在每个类中启动连接:

    $db = DB::getInstance(); // or any other way to initiate it
    $obj1 = new MyClass1($db);
    $obj2 = new MyClass2($db);
    

    这样,您始终可以决定要传递给每个类的 DB。此外,如果您也进行单元测试,这会带来一些优势 - 然后您可以通过提供测试数据库的链接甚至模拟/存根来测试每个类。

    【讨论】:

    • 感谢这么简单的依赖注入示例。 DI 的复杂性让我印象深刻。
    • 对。实际上,这种方式是我尝试的第一件事,除了在类之外启动数据库连接,然后通过 args 将其传递给主类。但是,我认为必须在每个构造函数中传递 db 链接,然后在每个类中执行 $this-&gt;db = $db 来访问整个类中的链接是非常糟糕的。它归结为与单例类几乎相同的东西。
    【解决方案2】:

    如果您使用魔术 __get 方法创建超类,您可以检查请求的属性的名称是否为 db,如果是,则自动从您的 DB 类中获取实例,如果没有像往常一样出错:

    <?php
    class Super
    {
        public function __get($name)
        {
               if($name=="db") {
                         return DB::getInstance();
               } else {
                         trigger_error("Undefined property", E_USER_NOTICE);
               }
        }
    }
    ?>
    

    【讨论】:

    • 这消除了原始单例方法的问题之一,即无法调用不同的数据库实例。但主要问题仍然存在。
    • 啊,我以为您的意思是不必实例化您的意思是重新连接的数据库,而不是显式调用该方法来初始化变量。对于您最终提出的解决方案(没有足够的编辑空间),您可以在 Super 类中使用 __get 方法。在那里您可以检查您要查找的属性的名称是否为 db,如果是,则 getDBConn(),如果不是,则照常出错。我将进行编辑以说明我的意思。
    • 太棒了!这样就更好了。我可以在类上使用构造函数,并且仍然可以访问this-&gt;db
    • 您可以编辑答案以指定这一点,以便我接受吗?谢谢。
    • 谢谢。对于未来的读者,请查看我的答案以获取有关扩展方法的进一步说明。
    【解决方案3】:

    所以,我想出了自己的答案。我不确定这是否是最佳方式,但就是这样。 使用与问题相同的数据库类,我创建了一个“超级”类来“保存”构造时的数据库链接。这样,只要我不在其他类上使用构造函数,我就可以扩展“Super”类,并访问$this-&gt;db,而无需在每个类中定义它。如果确实需要构造函数,我可以从中调用parent::__construct(),它也可以工作。

    class Super {
        protected $db;
    
        public function __construct() {
            $this->db = DB::getInstance();
        }
    }
    
    class Main extends Super {
    
        /* No constructor, 
           otherwise it will overwrite the Super 
           constructor and lack what we've done there. */
    
        public function start() {
            $this->db->query(something...); // works
        }
    
    }
    

    我还注入了几个类中需要的其他一些变量和函数。从那里,我可以在需要时选择在哪里扩展或不扩展“超级”类。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-08-10
      • 1970-01-01
      • 1970-01-01
      • 2015-05-10
      • 1970-01-01
      • 2013-12-26
      • 1970-01-01
      相关资源
      最近更新 更多