Когда использовать подготовленные выражения в 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