У меня есть следующие классы в PHP:
class Database {
...
}
class Product {
public function __construct() {
...
}
}
В настоящее время я думаю о наличии глобального экземпляра класса базы данных, в котором в методе __construct класса Product я проверил бы, был ли объект инициализирован следующим образом:
class Product {
public function __construct() {
if (!isset($db)) {
throw new Exception ('Database object not initialized.');
}
...
}
}
Это хорошая реализация? Если нет, что вы рекомендуете?
Мне кажется, что вы пытаетесь создать свой собственный ORM, и на практике это хорошо. Для больших проектов и для большего комфорта подумайте о принятии некоторых ORM, таких как Doctrine, Eloquent и т.д. (В зависимости от структуры).
Для подхода, который не использует инъекцию зависимости, может потребоваться создать экземпляр объекта базы данных в конструкторе. Давайте дадим пример, в котором используется одиночный элемент для предоставления объекта БД.
class Product {
private $pdo = null;
// other product properties here
public function __construct() {
// get db
try {
// set PDO object reference on this object
$this->pdo = PDOSingleton::getInstance();
} catch (Exception $e) {
error_log('Unable to get PDO instance. Error was: ' .
$e->getMessage();
// perhaps rethrow the exception to caller
throw $e;
}
// query DB to get user record
}
// other class methods
}
// example usage
$product = new Product(1);
При использовании инъекции зависимостей это может выглядеть следующим образом:
class Product {
private $pdo = null;
// other product properties here
// pass PDO object to the constructor. Enforce parameter typing
public function __construct(PDO $pdo) {
$this->pdo = $pdo;
// query DB to get product record
}
// other class methods
}
// example usage
// instantiate PDO object. This probably happens near beginning
// of code execution and might be the single instance you pass around
// the application
try {
$pdo = new PDO(...);
} catch (PDOException $e) {
// perhaps log error and stop program execution
// if this dependency is required
}
// somewhere later in code
$product = new Product($pdo);
Это может показаться лишь тонкой разницей, но разработчики, которые используют этот подход, так как это:
отделяет класс потребления от деталей того, как создать экземпляр зависимости. Почему класс пользователя должен знать, какой синглтон использовать, чтобы получить зависимость от PDO? Все классы должны заботиться о том, как работать с зависимостью (то есть, какие свойства и методы у нее есть), а не как ее создать. Это более точно следует принципу единой ответственности, который обычно требуется в ООП, поскольку пользовательский класс должен иметь дело с созданием представления пользователя, а не с созданием его зависимостей.
устраняет дубликат кода между классами, которым требуется зависимость, поскольку вам не нужна вся обработка в каждом классе при создании/создании зависимостей. В примере кода я устраняю необходимость потенциально обрабатывать неудавшееся создание БД внутри конструктора, так как я знаю, что у меня уже есть действительный объект PDO, переданный как параметр (если я не получил один переданный, я бы получил недопустимое исключение аргумента).
global $db;
в конструкторе класса Product?