Какие есть best practices в работе с PDO?

Добрый день.

В качестве хобби занимаюсь программированием на PHP(самый начальный уровень), как человеку с запущенным перфекционизмом головного мозга, меня больше интересует не сам результат, а изящность решений и кода.

Сейчас любое обращение к базе приводит к тому, что в коде появляется подобная "портянка":

function dinnerBase_getOrderTicket($base_connect, $users, $expiredtime){
    try {
        extract($base_connect);
        $dinnerBase = new PDO($host, $adm_user, $adm_password);
        $dinnerBase -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $dinnerBase->query("SET NAMES utf8");
        $dinnerBase->query("SET CHARACTER SET utf8");

        $query = "CREATE TABLE IF NOT EXISTS `:table_name` (
        ...
                $stmt = $dinnerBase -> prepare($query);
        $stmt -> execute(array(':table_name' => 'order_ticket'));
        }

    $dinnerBase = NULL;    
    } 
    catch (PDOException $e) {
    print "Error!: " . $e->getMessage() . "<br/>";
    die();
    }
}


Довольно объемно выходит, при этом код от обращения к обращению почти не меняется.

Вы могли бы накидать примеров кода с лучшими на ваш взгляд практиками использования PDO? Может стоит подключение к базе вывести в отдельную функцию которая возвращает объект PDO? Тогда как быть с конструкцией try-catch? Может стоит написать свою обертку для PDO? Но мне кажется это избыточно.
  • Вопрос задан
  • 3618 просмотров
Решения вопроса 1
Anonym
@Anonym
Программирую немного )
Напишите простенький синглтон в котором храните соединение с БД, ловите ошибки и т.д.
Или отнаследуйтесь от PDO.
Работать будет как-то так:
$db = DB::getConnection();
$db->exec('UPDATE ...', array(/* arguments */));
Ответ написан
Пригласить эксперта
Ответы на вопрос 5
FanatPHP
@FanatPHP
Чебуратор тега РНР
а как быть с конструкцией try-catch?

Никак. Если подумать, то эта конструкция здесь не нужна: www.phpfaq.ru/pdo#exceptions

По поводу же синглтона, то если выкинуть всё лишнее, и использовать РНР5, то получится так
class DB
{
    protected static $instance = null;

    final private function __construct() {}
    final private function __clone() {}

    public static function instance()
    {
        if (self::$instance === null)
        {
            $dsn = 'mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset='.DB_CHARSET;
            self::$instance = new PDO($dsn, DB_USER, DB_PASS);
            self::$instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            self::$instance->query("SET NAMES ".DB_CHARSET);
        }
        return self::$instance;
    }
    public static function __callStatic($method, $args) {
        return call_user_func_array(array(self::instance(), $method), $args);
    }
}


и обращаться напрямую

$stmt = DB::prepare($query);
Ответ написан
miraage
@miraage
Старый прогер
Да, конечно, незачем плодить 100 соединений.
Если у Вас преобладает функциональный стиль, тогда попробуйте что-то вроде такого:

function pdo()
{
    static $pdo;

    if (!$pdo) {
        // в первый раз инициализируем объект PDO
    }

    return $pdo;
}


И дальше пишите что Вам надо. :)

$stmt = pdo()->prepare('UPDATE order_tickets SET status = :stid WHERE id = :id');
...
Ответ написан
omun
@omun
Обычно перфекционистский подход следующий: от PDO наследуется класс, в котором определяется логика работы с БД.
Это не мешает ему одновременно быть синглтоном, как указал @Anonym.
Внутри класса, помимо подключения, можно определить свои функции к бд, тогда само соединение вообще не надо будет никуда возвращать, работать только с классом.
Например, вы определяете функцию myPDO::update(), в которую передаете текст запроса с именованными параметрами и сами эти параметры в ассоциативном массиве. Внутри функции вы выполняете обычные PDO функции и можете добавить свою обработку try-catch, тогда она не будет здесь захламлять код на каждом вызове.
Ответ написан
Комментировать
Думаю разберётесь...
//---------------- Процедура подключения к базе данных -----------------------//
function dbconnect() {
	global $database;
	if (!isset($database)) {
		// Соединение по IP самое быстрое
		// Сразу задаём кодировку соединения
		$database = new PDO('mysql:host=127.0.0.1;dbname=base_name', "Vita", "god", array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''));
		// Устанавливаем уровень показа ошибок базы
		$database->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
	}
	return true;
}
//----------------------------------------------------------------------------//

//--------------------- Функция выполнения запросов --------------------------//
function sql_query($query) {
	global $errors;
	global $database;
	
	try { 
      if (dbconnect()) $return = $database->query($query);
   } 
   catch (PDOException $e) { 
      $error = $e->getMessage();
  		writelog('sql_error', date("y.m.d H:m:s")."\t".$error);
		$errors .= $error;
		return false;
   }

	return $return;
}
//----------------------------------------------------------------------------//

//------------------------ Процедура записи в лог фаил -----------------------//
function writelog($typelog, $log_text) {
	file_put_contents('logs/'.$typelog.'.txt', "$log_text\r\n", FILE_APPEND | LOCK_EX);
}
//----------------------------------------------------------------------------//
Ответ написан
@DukeRaul Автор вопроса
Спасибо за ваши ответы, очень помогли. По совету написал небольшой синглтон, подскажите это нормальная практика кода?

<?php
class DB {
    protected static $_instance = null;
    public $_pdo = null;

    private function __construct() {
    try {
        $this -> _pdo = new PDO(
                'mysql:host=localhost;dbname=xxx', 'root', 'xxx');
        $this -> _pdo -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $this -> _pdo -> query("SET NAMES utf8");
        $this -> _pdo -> query("SET CHARACTER SET utf8");
        } 
    catch (PDOException $e) {
        print "Error!: " . $e->getMessage() . "<br/>";
        die();
        }
    }

    public static function getInstance() {
    if (self::$_instance === null) {
        self::$_instance = new self;
        } 
    return self::$_instance;
    }

    private function __clone() {
    }

    private function __wakeup() {
    }     
}
?>


Обращение к инстансу:

$order_ticket_query = "CREATE TABLE IF NOT EXISTS `:table_name` (
                    `ID` INT AUTO_INCREMENT NOT NULL,
                    `oID` varchar(10),
                    `week` INT,
                    `name` varchar(70),
                    `expired` DATETIME,
                    `created` DATETIME,
                    `use` BOOL,
                    PRIMARY KEY (`ID`)
                    ) CHARACTER SET utf8 COLLATE utf8_general_ci;";
                           
        $stmt = DB::getInstance() -> _pdo -> prepare($order_ticket_query);
        $stmt -> execute(array(':table_name' => 'order_ticket'));
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы