在网站项目后端的范围内,我非常努力地理解依赖注入以及如何避免全局变量。在这里,我正在使用PHP。
// MySQLDatabase.php
class MySQLDatabase
{
private $database;
public function __construct($db_host, $db_username, $db_password, $db_name) {
$this->database = new mysqli(
$db_host,
$db_username,
$db_password,
$db_name
);
}
}
// User.php
class User {
public function __construct($database, $id);
}
// Image.php
class Image {
public function __construct($database, $id);
}
$database = new MySQLDatabase($dbh, $dbu, $dbp, $dbn);
$existingUser = new User($database, $userID);
$existingImage = new Image($database, $imageID);
我知道,为了保持代码的可测试性,可包含性且没有全局变量,我需要注入依赖项。我很困惑的地方是 where 实例化这些依赖关系。上面的代码似乎回答了有关依赖注入的每个问题,他们说:“这就是您的方法!”但是他们从不解释如何设置程序的其余部分,以便可以将依赖项挂钩在一起。
我首先想到了使用引导程序文件,该文件首先实例化依赖项,以供程序的其余部分使用:
// bootstrap.php
$database = new MySQLDatabase($dbh, $dbu, $dbp, $dbn);
但是对我来说,这似乎是我在这里创建一个全局对象。我的几乎每个页面都需要数据库,并且这里的这个数据库将在每个脚本中传递……对我来说似乎像一个单身汉(每个人都说避免这样做)。
我可以逐页实例化数据库。这意味着user.php页面将不使用引导文件,而仅提取其所需的依赖项(数据库,用户类等)。这会在每个页面上发生(user_images.php,login.php)。但这似乎是代码重复,因为每个页面都将包含一些相同的代码。我还考虑过要创建一个静态类型的类,以使其更易于实例化数据库,您可以通过文件来加载该数据库:
// MySQLDatabase.php
class SpecificDatabase
{
private static $initialized = false;
public static function initialize($db_host, $db_username, $db_password, $db_name) {
if(self::$initialized) return;
self::$database = new MySQLDatabase(
$db_host,
$db_username,
$db_password,
$db_name
);
self::$initialized = true;
}
}
但是在这种情况下,您每次需要使用数据库时都必须始终获得db凭据来初始化数据库(除非您在此处对其进行了硬编码,但是我认为这同样糟糕)。在我的代码中几乎每个页面上都有这样的东西:
require_once(__DIR__.'/vendor/autoload.php');
require_once(__DIR__.'/utilities/database/SpecificDatabase.php');
require_once(__DIR__.'/entities/User.php');
// load environment variables
$dotenv = new Dotenv\Dotenv(__DIR__);
$dotenv->load();
$database = new SpecificDatabase(getenv('DATABASE_HOST'), getenv('DATABASE_USERNAME'), getenv('DATABASE_PASSWORD'), getenv('DATABASE_NAME'));
$user = new User($database, $userID);
有人可以帮助我更好地理解这一点吗?我真的想成为一名出色的程序员。有一些障碍需要我花更多的时间来理解,我认为这可能归结为一些简单的误解,尤其是词汇上的误解-例如,我认为避免重复 AND 避免全局变量。我对依赖注入的大部分研究都是从类内部拉出依赖的结论。但是当他们被拉出时,他们会去哪里...?