после прочтения этого вопроса, я задаюсь вопросом, может ли кто-нибудь помочь мне понять, как правильно реализовать инъекцию зависимостей с помощью этих классов PHP:
class DBClass { private $mMysqli; function __construct(mysqli $database) { $this->mMysqli=$database; } function __destruct() { $this->mMysqli->close(); } public function listUsers() { $query='SELECT * FROM Utente;'; $resultset=$this->mMysqli->query($query); while($row = $resultset->fetch_array(MYSQLI_ASSOC)) { echo $row['username']; echo $row['pwd']; echo "<br />\n"; } } public function runQuery($query) { return $resultset=$this->mMysqli->query($query); } public function getConnection() { return $this->mMysqli; } }
Класс сеанса:
class Session { private $_session; public $maxTime; private $database; public function __construct(DBClass $database) { $this->database=$database; $this->maxTime['access'] = time(); $this->maxTime['gc'] = get_cfg_var('session.gc_maxlifetime'); session_set_save_handler(array($this,'_open'), array($this,'_close'), array($this,'_read'), array($this,'_write'), array($this,'_destroy'), array($this,'_clean') ); register_shutdown_function('session_write_close'); session_start(); ... } }
Пользовательский класс (для получения подробной информации о пользователе, который в настоящий момент вошел в систему):
class User { private $username; private $role; private $session; function __construct($session) { $this->session=$session; ... } }
Наружно:
$connection=new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_DATABASE); $database=new DBClass($connection); $session=new Session($database); $user=new User($session);
Правильно ли это?
Да. Теперь вы вводите зависимости через конструктор, который обеспечивает меньшую связь. Теперь вы можете легко заменить эти зависимости, например, когда UnitTesting вы можете заменить их на Mocks.
У вас все еще есть некоторая связь, хотя, используя конкретный DBClass как TypeHint вместо интерфейса . Поэтому, когда вы захотите использовать другой DBClass, его нужно будет назвать DBClass. Вы могли бы достичь более свободной связи путем кодирования с интерфейсом, который конкретные классы должны реализовать вместо этого.
Чтобы создать только отдельные экземпляры класса (как задано в комментариях), вы можете использовать Singleton (например, предложенный Кевином Пено) или Factory для создания и отслеживания, если экземпляр был создан еще. Или используйте контейнер службы DI, который похож на завод, но не то же самое. Он создает и управляет объектами для вас.
В библиотеке Symfony Components есть контейнер для инъекций с отличной документацией и введение в тему о том, как еще больше улучшить DI с помощью контейнерных контейнеров. Контейнеры также могут использоваться для ограничения экземпляров. Проверьте это.