PHP pdo экземпляр как частное статическое свойство

Я пытаюсь создать свой веб-сайт на основе ООП, но у меня возникли проблемы с проектированием подключения к базе данных. В настоящее время я создаю частный статический объект PDO в абстрактном классе Connector. Очевидно, что все, что должно взаимодействовать с базой данных, будет расширять этот класс. Я перескакивал туда и обратно о том, как убедиться, что в сценарии есть только одно соединение или объект PDO, потому что некоторым страницам потребуется больше одного класса, который расширяет Connector. Многие люди, похоже, рекомендуют шаблон Singleton для этой цели, но то, как я сейчас это делаю, похоже, делает то же самое.

Вот мой текущий код.

abstract class Connector { private static $dbh; public function __construct() { try { self::$dbh = new PDO(...); self::$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch(PDOException $e) { die($e->getMessage()); } } public function getDB() { return self::$dbh; } } 

Тогда любые подклассы использовали бы это так.

 class Subclass extends Connector { public function interactWithDB() { $stmt = $this->getDB()->prepare(...); // etc... } } 

Теоретически каждый экземпляр подкласса всегда должен иметь доступ к тому же экземпляру PDO, я думаю. Действительно ли этот код имеет смысл, и почему-то я неправильно понимаю статические свойства? Это плохой дизайн / практика, и у Синглтона больше преимуществ?

Комментарий, если что-то непонятно, спасибо!

РЕДАКТИРОВАТЬ:

Класс Connector не должен существовать только для хранения объекта PDO. Деструктор закрывает соединение (делает его нулевым) и содержит такие функции, как isValueTaken, который проверяет, уже ли значение в базе данных. Он имеет следующие абстрактные функции

 abstract function retrieveData(); abstract function setData(); 

Например, у меня есть класс User, который расширяет Connector. Он определяет setData () для регистрации пользователя в базе данных. Я не знаю, влияет ли это на ответ.

Related of "PHP pdo экземпляр как частное статическое свойство"

Очевидно, что все, что должно взаимодействовать с базой данных, будет расширять этот класс.

Это действительно не имеет смысла с точки зрения ООП. Когда какой-то класс расширяет другой класс, который подразумевает связь «есть». Если вы идете по этому маршруту, вам будет трудно не нарушать OCP, который является одной из букв в SOLID .

Я перескакивал туда и обратно о том, как убедиться, что в сценарии есть только одно соединение или объект PDO, потому что некоторым страницам потребуется больше одного класса, который расширяет Connector.

Легко! Просто создайте один экземпляр.

Многие люди, похоже, рекомендуют шаблон Singleton для этой цели, но то, как я сейчас это делаю, похоже, делает то же самое.

Многие такие люди не имеют понятия о принципах ООП. Использование singleton просто вводит «причудливый» глобальный экземпляр / состояние .

Действительно ли этот код имеет смысл, и почему-то я неправильно понимаю статические свойства?

Честно говоря, это больше непонимание ООП.

Это плохой дизайн / практика, и у Синглтона больше преимуществ?

См. Выше.


То, что вы должны сделать (в ООП), вводит соединение с базой данных в классы, которые в ней нуждаются. Это делает ваш код слабо связанным, что, в свою очередь, делает ваш код более удобным для обслуживания, тестируемым, отлаживаемым и гибким.

Также я не понимаю, почему вам нужно создать класс базы данных для подключения pdo, потому что сам PDO API уже является ООП. Поэтому, если у вас нет реальной причины для написания адаптера (может быть, потому что есть некоторые) для PDO, я бы просто отказался от него.

Мой € 0.02

В ответ на ваше редактирование:

Класс Connector не должен существовать только для хранения объекта PDO. Деструктор закрывает соединение (делает его нулевым).

Часто нет необходимости закрывать соединение. Соединение будет автоматически закрыто после обработки запроса (если мы не говорим о постоянном соединении).

и он содержит такие функции, как isValueTaken, который проверяет, уже ли значение в базе данных. Он имеет следующие абстрактные функции

Это похоже на работу для другого класса.

Например, у меня есть класс User, который расширяет Connector. Он определяет setData () для регистрации пользователя в базе данных. Я не знаю, влияет ли это на ответ.

Ничего не стоит. Пользователю не нужно наследовать базу данных. Разве это не странно. Пользователь, наследующий базу данных (я не хочу встречаться с этим человеком). Вы должны ввести соединение с базой данных в Пользователь, если это необходимо.

Предисловие

Одиночный подход, как правило, неодобрительно. У вас будут хищники .


В основном вы спрашиваете, как настроить соединение и сделать его доступным по всему миру. Обычно это называется глобальным состоянием . Вы можете достичь этого, используя класс контейнера и статические методы.

Вот пример

 namespace Persistence\Connection\Config; interface PDOConfig { public function getDSN(); public function getUsername(); public function getPassword(); public function getDriverOptions(); } class MySqlConfig implements PDOConfig { private $username; private $password; private $db; private $host = 'localhost'; private $charset = 'utf8'; public function __construct($username, $password, $db) { $this->username = $username; $this->password = $password; $this->db = $db; } // getters and setters, etc public function getDSN() { return sprintf('mysql:host=%s;dbname=%s;charset=%s', $this->host, $this->db, $this->charset); } public function getDriverOptions() { return [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ]; } } namespace Persistence\Connection; use Persistence\Connection\Config\PDOConfig; class Registry { private static $connection; private static $config; public static function setConfig(PDOConfig $config) { self::$config = $config; } public static getConnection() { if (self::$connection === null) { if (self::$config === null) { throw new RuntimeException('No config set, cannot create connection'); } $config = self::$config; self::$connection = new \PDO($config->getDSN(), $config->getUsername(), $config->getPassword(), $config->getDriverOptions()); } return self::$connection; } } 

Затем, в какой-то момент (в начале) цикла выполнения приложения

 use Persistence\Connection\Config\MySqlConfig; use Persistence\Connection\Registry; $config = new MySqlConfig('username', 'password', 'dbname'); Registry::setConfig($config); 

Затем вы можете использовать

 Registry::getConnection(); 

в любом месте вашего кода, чтобы получить экземпляр PDO.

Просто обратите внимание, если кто-нибудь читает это, если кто-либо использует приведенный выше фрагмент кода Филом, не забудьте использовать черную черту внутри PDO внутри getDriverOptions (), чтобы ссылаться на глобальное пространство имен. он должен выглядеть так.

 public function getDriverOptions() { return [ \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, \PDO::ATTR_EMULATE_PREPARES => false, \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC ]; }