PHP类 - 全局或__construct

时间:2015-04-23 09:28:39

标签: php class

所以我遇到了PHP类的“问题”。

我有一些需要彼此功能的类,所以目前我正在做以下事情:

$db = new blueConnect;
$core = new blueCore($db);
$users = new blueUsers($db, $core);

然后在文件中:

public function __construct(blueConnect $db, blueCore $core) {
    $this->db = $db;
    $this->core = $core;
}

但是,不是为每个需要附加功能的文件执行此操作,而是编写

更好
global $db, $core

在每个需要它的函数中?

4 个答案:

答案 0 :(得分:3)

您所谈论的模式的名称简称为“依赖注入”或 DI

根据您的项目使用全局可能会在短期内解决问题,但如果您计划创建一个大项目,您稍后将测试并与多人共享,您希望避免使用全局。 - 你无法测试或调试那些东西

(坏)解决方案是让您的数据库和核心类使用 Singleton Pattern 来避免全局但具有相同的效果。 (不可测试,不可配置

public function __construct() {
    $this->db = blueConnect::getInstance();
    $this->core = blueCore::getInstance();
}

解决方案通常是创建工厂功能,以创建需要数据库和核心的所有服务

public function createService($name) {
    $serviceClass = 'blue'.ucfirst($name).'Service';
    return new $serviceClass($this->getDatabase(), $this->getCore());
}

此功能通常是注册表的一部分或更好的 DI容器,例如PIMPLE

每个服务只有一个实例的示例:

public function createService($name) {
    $serviceClass = 'blue'.ucfirst($name).'Service';

    static $services = array();
    if(!isset($services[$name])) {
        $services[$name] = new $serviceClass($this->getDatabase(), $this->getCore());
    }

    return $services[$name];
}

请注意,由于容器内部存在“全局”状态,因此不应使用Registry / DI容器进行测试。 (例如,两次获取相同的服务)

答案 1 :(得分:2)

我不会使用全局变量。

理由:

  1. 这不是OOP方式。

  2. 难以调试。

  3. 生成的代码不可测试。如果您希望单元测试涵盖您的应用程序,您应该像现在一样使用Dependcy Injection。我会试着简要解释一下原因。正如其名称所暗示的单元测试就是:测试应用程序的单个单元,即您的类(它们的public方法)。

    现在让我们假设您使用在应用中的某个位置设置的全局变量。您将无法将blueUsers类作为独立单元进行测试,因为您需要实例化$db$core对象。因此,您将无法仅包含blueUsers.php文件并测试该类,因为您将需要应用程序的其他部分(定义全局变量$db$core的那些部分)。

    另一方面,如果您使用Dependcy Injection,则不会遇到这样的问题。为了测试blueUsers类,您需要做的唯一事情就是包括类,创建依赖项$db$core的模拟,并将它们传递给{ {1}}构造函数。

  4. 这是一个很好的source,有关如何编写可测试和可维护代码的更详细说明。

    here您可以找到有关模拟的更多信息,以及使用它是否以及您可以从中受益。

答案 2 :(得分:1)

我使用单线来包含全局对象。它可以被其他对象轻松访问,并且可以安全地访问这些变量:

final class GlobalObjects
{
    public static function Instance()
    {
        static $inst = null;
        if ($inst === null) {
            $inst = new GlobalObjects();
        }
        return $inst;
    }

    private function __construct() {
        $db = new blueConnect;
        $core = new blueCore($db);
    }

    public function getDb() { return $this->db; }

    public function getCore() { return $this->core; }
}

// ...

public function __construct() {
    $this->db = GlobalObjects::Instance()->getDb();
    $this->core = GlobalObjects::Instance()->getCore();
}

我想到的另一种方法,一种更简单,更脏的方法是:由于这些变量是全局对象,因此可能值得将它们定义为常量以避免错误:

define( "db", new blueConnect );
define( "core", new blueCore($db) );

$users = new blueUsers($db, $core);

然后

public function __construct() {
    global $db, $core;

    $this->db = $db;
    $this->core = $core;
}

答案 3 :(得分:0)

如果参数是动态和可变的,您应该在构造函数中传递它们,因此新的<div id="json"></div> <script> var obj = {"data": [ { "name": "Rehan", "location": "Pune", "description": "hello hi", "created_by": 13692, "users_name": "xyz", }, { "name": "Sameer", "location": "Bangalore", "description": "how are you", "created_by": 13543, "users_name": "abc", } ]} var divId = document.getElementById("json") for(var i=0;i<obj.data.length;i++) for(var keys in obj.data[i]){ console.log(keys +"-->"+obj.data[i][keys]); divId.innerHTML = divId.innerHTML + "<br/>"+ keys +"-->"+obj.data[i][keys]; } </script> 更好。但是如果这些是静态参数,并且在初始化类时不需要传递它们,则应该定义为全局。