Я пытаюсь понять, как использовать PDO с классом «соединение».
class db { private static $dbh; private function __construct(){} private function __clone(){} public static function connect() { if(!self::$dbh){ self::$dbh = new PDO("mysql:host=localhost;dbname=database", "user", "password"); self::$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } return self::$dbh; } final public static function __callStatic( $chrMethod, $arrArguments ) { $dbh = self::connect(); return call_user_func_array(array($dbh, $chrMethod), $arrArguments); } }
Я сделал это из http://php.net/manual/en/book.pdo.php и немного изменил переменные, но мне интересно, как я потом подключаюсь к объекту соединения PDO в этом классе db?
$dbh = new db; //intiate connection??? $stmt = $dbh->prepare("SELECT * FROM questions WHERE id = :id"); // or should I do db::prepare.. ??? $stmt->bindParam(':id', $_GET['testid'], PDO::PARAM_INT); if ($stmt->execute()) { while ($row = $stmt->fetch()){ print_r($row); } }
Любые идеи, пожалуйста? благодаря
Это более или менее, как я это делаю. Я не уверен, что это лучший способ сделать это, но это работает для меня.
Мой заводский класс – это CORE моего кода. Отсюда я создаю все классы, с которыми я работаю. Мой заводский класс сохраняется в отдельном файле factory.class.php
.
Имея фабричный класс, мне нужно только включить файлы классов только один раз. Если бы у меня не было этого, я бы включил файлы классов для каждого файла, который должен был его использовать. Если мне нужно обновить имя файла класса позже, мне нужно только сделать обновление в файле фабричного класса.
Еще одна причина создания фабричного объекта заключалась в сокращении числа соединений с БД.
Я сохраняю каждый класс как отдельный файл
Фабричный класс
include_once('person.class.php'); include_once('tracking.class.php'); include_once('costAnalyzis.class.php'); include_once('activity.class.php'); class Factory { function new_person_obj($id = NULL) { return new Person(Conn::get_conn(), $id); } function new_tracking_obj($id = NULL) { return new Tracking(Conn::get_conn(), $id); } function new_costAnalyzis_obj() { return new CostAnalyzis(Conn::get_conn()); } function new_activity_obj() { return new Activity(Conn::get_conn()); } }
Класс подключения
// I have this class in the same file as Factory class // This creates DB connection and returns any error messages class Conn { private static $conn = NULL; private function __construct() {} private static function init() { $conf = self::config(); try { self::$conn = new PDO($conf['dsn'], $conf['user'], $conf['pass'], array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8")); } catch (PDOException $e) { // We remove the username if we get [1045] Access denied if (preg_match("/\b1045\b/i", $e->getMessage())) echo "SQLSTATE[28000] [1045] Access denied for user 'name removed' @ 'localhost' (using password: YES)"; else echo $e->getMessage(); } } public static function get_conn() { if (!self::$conn) { self::init(); } return self::$conn; } // I used to get login info from config file. Now I use WordPress constants private static function config() { $conf = array(); $conf['user'] = DB_USER; //$config['db_user']; $conf['pass'] = DB_PASSWORD; //$config['db_password']; $conf['dsn'] = 'mysql:dbname='.DB_NAME.';host='.DB_HOST; return $conf; } }
Различные объекты класса
Это ваши занятия. Здесь вы работаете с вашими данными. В моем собственном коде я использую трехуровневую архитектуру, разделяющую презентацию, с уровня бизнес-уровня и объекта данных.
class Person extends PersonDAO { function getPersonData($id) { $result = parent::getPersonData($id); // Here you can work with your data. If you do not need to handle data, just return result return $result; } } // I only have SQL queries in this class and I only return RAW results. class PersonDAO { // This variable is also available from you mother class Person private $db; // Constructor. It is automatically fired when calling the function. // It must have the same name as the class - unless you define // the constructor in your mother class. // The &$db variable is the connection passed from the Factory class. function PersonDAO (&$db) { $this->db = &$db; } public function get_data($id) { $sql ="SELECT a, b, c FROM my_table WHERE id = :id"; $stmt = $this->db->prepare($sql); $stmt->execute(array(':id'=> $id)); $result = $stmt->fetchAll(PDO::FETCH_ASSOC); return $result; } public function get_some_other_data() { $sql ="SELECT a, b, c FROM my_table_b"; $result = $stmt->fetchAll(PDO::FETCH_ASSOC); return $result; } }
Сделайте то же самое для своих других классов.
Объединяя все это
Обратите внимание, что мы включаем только один файл, заводские файлы. Все другие файлы классов включены в файл класса Factory.
// Include factory file include_once('factory.class.php'); //Create your factory object $person = Factory::new_person_obj(); //Get person data $data = $person->getPersonData('12'); // output data print_r($data);
Как я понял, вы хотите иметь «класс соединения», который реализует ленивую загрузку для экземпляра PDO. И тогда вы хотите, чтобы объекты в вашем коде имели доступ к этому соединению из любого места в коде, эффективно создавая синглтон.
Не делай этого.
Вы очищаете глобальное состояние в своем приложении, и все ваши классы с поддержкой DB тесно связаны с NAME класса соединения.
Я бы порекомендовал немного другой подход. Как уже указывал @Steven , вы должны использовать фабрику для создания объектов, для которых требуется соединение с БД.
Вот упрощенная реализация.
class DataMapperFactory { protected $provider = null; protected $connection = null; public function __construct( Closure $provider ) { $this->provider = $provider; } public function create( $name) { if ( $this->connection === null ) { $this->connection = call_user_func( $this->provider ); } return new $name( $this->connection ); } }
Вы бы использовали его как это:
$provider = function() { $instance = new PDO('mysql:......'); $instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $instance->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); return $instance; }; $factory = new DataMapperFactory( $provider );
Теперь каждый раз, когда вы выполняете $factory->create('SomeClass')
, он создаст новый экземпляр этого класса и предоставит ему правильное соединение DB в конструкторе. И, когда он будет выполнен в первый раз, он откроет соединение с БД.