Когда использовать подготовленные выражения в PDO?

1. lekt (22.09.2013 / 04:18)
Вот решил проект переписать с использованием PDO и возник вопрос озвученный в названии темы.
К примеру, есть у меня класс в котором есть метод get_value(), его можно описать используя подготовленные выражения, вот так:
function get_value($value) {
        if ($this->id == 0)
            return 'error';
        else {
            global $db;
            try {
                
                $smtp = $db->prepare("SELECT '".$value."' FROM `user` WHERE `id`=:id");
                $smtp->bindParam(':id', $this->id, PDO::PARAM_STR);
                $smtp->execute();
                $a = $smtp->fetch(PDO::FETCH_ASSOC);
                return $a[$value];
            } catch (PDOException $e) {
                msg('error', $e->getMessage());
            }
        }
    }

Или вот так:
function get_value($value) {
        if ($this->id == 0)
            return 'error';
        else {
            global $db;
            try {
                $smtp = $db->query("SELECT '".$value."' FROM `user` WHERE `id`='".$this->id."'");
                $a = $smtp->fetch(PDO::FETCH_ASSOC);
                return $a[$value];
            } catch (PDOException $e) {
                msg('error', $e->getMessage());
            }
        }
    }

Как лучше?
Во втором конечно писанины меньше, но везде пишут о прибавке к скорости при использовании подготовленных.

2. Станислав Крунич (22.09.2013 / 06:55)
Во втором примере у тебя нет prepareStatement() выражений. конечно первый лучше. Подготовленные выражения используются как замена mysql_real . .. итд. И там в твом случае обработка должна стоять PARAM_INT

3. lekt (22.09.2013 / 17:19)
Stanislav-WEB, ну например в этом методе по большому счету не нужна фильтрация, id приходит в конструктор из $_SESSION['id'] при создании объекта, на который юзер не имеет влияния, оно приходит из базы при авторизации, то есть подменить его нельзя.

4. Александр (22.09.2013 / 17:32)
1. lekt, по поводу прибавки скорости...
тут немного о другом.
например
foreach($arr as $val)
{
$db->query('UPDATE `user` SET `time`='.time().' WHERE `id`="'.$val.'"');
}
1000 юзеров - 1000 запросов. Не есть гуд.
вот тут придет на помощь подготовленый шаблон
$template = prepare('UPDATE `user` SET `time`='.time().' WHERE `id`=:id');
foreach($arr as $val)
{
                $template->bindParam(':id', $val, PDO::PARAM_INT); 
                $template->execute(); 
}


5. alert (22.09.2013 / 17:33)
Всегда используй. Хуже не будет.

6. lekt (22.09.2013 / 17:42)
4. rastoman, то есть в данном методе можно спокойно обойтись и без подготовленных выражений ?

7. MarkizDeSad (22.09.2013 / 18:03)
lekt (22 Сентября 2013 / 13:42)
4. rastoman, то есть в данном методе можно спокойно обойтись и без подготовленных выражений ?
Абсолютно согласен.
Если запрос используется однократно и параметром является число (INT), то подготовленные выражения не нужны.

8. Станислав Крунич (22.09.2013 / 20:03)
Применяй тогда фильтрацию там где она нужна - на входе. Это тоже можно ускорить  SET `time`='.time().' . Не стоит использовать функции в запросе, встроенный sql кэш не работает с NOW(). php rand() итп . . . Все то что динамически меняет свое поведение. Лучше будет вынести в обычную переменную

9. lekt (22.09.2013 / 22:48)
Появилась проблемка, не имеет отношения непосредственно к вопросу темы, но задам тут ибо тоже связано с pdo
есть такой код:
$id = text::num($_GET['id']);
try{
    $query = $db->query("SELECT * FROM `Server` WHERE `id`='".$id."'");
    if ($query->fetchColumn() !== 0){
        $x = $query->fetch(PDO::FETCH_ASSOC);
        include_once '' . $x['type'] . '_server.php';
    }else {
        msg('error', 'Сервер недоступен');
    }
}catch (PDOException $e){
    msg('error', $e->getMessage());
}
и вот почему-то массив $x пустой

а если например написать так:
$id = text::num($_GET['id']);
try{
    $query = $db->query("SELECT * FROM `Server` WHERE `id`='".$id."'");
    $x = $query->fetch(PDO::FETCH_ASSOC);
    include_once '' . $x['type'] . '_server.php';
    
}catch (PDOException $e){
    msg('error', $e->getMessage());
}

все норм.

даже если написать так:
$id = text::num($_GET['id']);
try{
    $query = $db->query("SELECT * FROM `Server` WHERE `id`='".$id."'");
    $count = $query->fetchColumn;
    $x = $query->fetch(PDO::FETCH_ASSOC);
    include_once '' . $x['type'] . '_server.php';
    
}catch (PDOException $e){
    msg('error', $e->getMessage());
}

массив тоже пуст.

никаких ошибок при этом нет, кроме
Warning: include_once(_server.php) [function.include-once]: failed to open stream: No such file or directory
из-за пустого массива.
Кто-то знает в чем дело?

10. Александр (22.09.2013 / 23:01)
fetchColumn() или fetchColumn(0).
!== 0 это не правильно в данной ситуации. Нужно !=

Добавлено через 05:01 сек.
так же если тебе нужен только type, зачем вызывать всю таблицу?
$query = $db->query("SELECT `type` FROM `Server` WHERE `id`='".$id."'"); 
    if ($type=$query->fetchColumn(0) && file_exists($type . '_server.php')){ 
        include_once $type . '_server.php';


11. Алексей (22.09.2013 / 23:24)
global $db; - пора от этого избавлятся уже)

12. lekt (22.09.2013 / 23:43)
10. rastoman, вся таблица вызывается так как в последующем будет использоваться в файле который инклудится

Добавлено через 01:13 сек.
ByKuznec (22 Сентября 2013 / 18:24)
global $db; - пора от этого избавлятся уже)
Как мне от этого избавится ? если эту строку удалить, то ничего не выйдет

Добавлено через 09:17 сек.
rastoman (22 Сентября 2013 / 18:01)
fetchColumn() или fetchColumn(0).
!== 0 это не правильно в данной ситуации. Нужно !=
]
как раз нужно !== с != не так работало, но всеравно спасибо, натолкнул на правильное решение
вот так работает:
$id = text::num($_GET['id']);
try{
    $query = $db->query("SELECT * FROM `Server` WHERE `id`='".$id."'");
    $x = $query->fetch(PDO::FETCH_ASSOC);
    if ($query->fetchColumn() !== 0){
        include_once '' . $x['type'] . '_server.php';
    }else {
        tank_msg('error', 'Сервер недоступен');
    }
}catch (PDOException $e){
    msg('error', $e->getMessage());
}
то есть сначала $x = $query->fetch(PDO::FETCH_ASSOC);, а потом $query->fetchColumn() .
если поменять местами, то не работает почему то

13. Александр (23.09.2013 / 01:03)
а вообще можно так
if($query->rowCount() >0)
{
$x = $query->fetch(PDO::FETCH_ASSOC);
include_once '' . $x['type'] . '_server.php';


14. lekt (23.09.2013 / 02:06)
13. rastoman, дело не в том, что условие не срабатывало.
Дело в том, что если сделать так :
echo $query->rowCount();
print_r($query->fetch(PDO::FETCH_ASSOC)) ;

Выводилась только единица (это $query->rowCount()), а массив якобы пустой.

А если так:
print_r($query->fetch(PDO::FETCH_ASSOC)) ;
echo $query->rowCount();
То выводилось содержимое массива и единица.
Вот в чем загадка, лично для меня. Может кто-то знает почему так

15. Станислав Крунич (23.09.2013 / 17:52)
Синглтон делать и подключать через конструктор, чтобы не использовать global $db. . . Вообще много способов

16. lekt (23.09.2013 / 21:59)
15. Stanislav-WEB, Какие еще? Почитал про синглтон, и как то у людей двоякое мнение о нем

17. Станислав Крунич (23.09.2013 / 22:31)
Он как раз для твоей задачи. Просто чтобы там нибыло. Вызывай его в конкрукторе , например protected $_db;. . . Затем конструктор . В нем this->_db = insance; и используй в классе. Во всех наследниках будет доступен. . . Домой приду скину пример

18. Алексей (23.09.2013 / 22:41)
17. Stanislav-WEB, во-во, за ето и я имел ввиду, а то global-global уже как быдлокодинг. Хотя многие еще его используют.

19. lekt (23.09.2013 / 23:15)
17. Stanislav-WEB, жду примера, везде пишут про вызов через статический метод

20. Станислав Крунич (24.09.2013 / 00:57)
class My {

	protected $_db = null;
	
	function __construct()
	{
		if($this->_db == null) $this->_db = DBConnect::getInstance(); // обьявить синглтон c PDO коннектом который выше должен быть подключен
	
	}
	
	// Все тра ля ля
	//$this->..db-> // как объект хранящий PDO объект
}


URL: https://visavi.net/topics/39024