@Michele

Затыки с PDOStatement::execute и MySQL — куда копать?

Уважаемые старшие товарищи, помощи прошу. Кажется, проблема проста, а не идёт!

При выполнении скрипта натыкаюсь на
Fatal error: Uncaught PDOException: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''categories'' at line 1


Вот мой труд (собрал всё в один файл):

<?php

$dsn = 'mysql:host=localhost;dbname=brand;charset=utf8';
$user = 'root';
$password = '';

function dbConnect($dsn, $user, $password) {
    try {
        $dbh = new PDO( $dsn, $user, $password );
        $dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
        return $dbh;
    } catch( PDOException $e ) {
        $errmsg = 'Подключение не удалось: ' . $e->getMessage();
        return $errmsg;
    }
}

function getNames( $db, $tableName, $fieldName ) {
    $sql = 'SELECT :fieldName FROM :tableName;';
//    $sql = 'SELECT category_name FROM categories;';
    $stmnt = $db->prepare( $sql );
    $stmnt->bindParam( ':fieldName', $fieldName );
    $stmnt->bindParam( ':tableName', $tableName );
    $stmnt->execute();
    
//    var_dump( $stmnt->errorInfo() );

    $res = $stmnt->fetchAll( PDO::FETCH_COLUMN, 0 );
    return $res;
}

$db = dbConnect( $dsn, $user, $password );
print_r( getNames( $db, 'categories', 'category_name' ) );

Если раскомментить SQL-запрос "в лоб", то всё работает:
Array ( [0] => WOMEN [1] => MAN [2] => WOMAN'S FOOTWEAR [3] => MAN'S FOOTWEAR [4] => OTHERS )

А вот если биндить параметры, то нет. Много перепробовал (bindValue тоже). Очень прошу меня направить в нужное русло, так как php только начинаю учить, и хочется понимать, так сказать, его механизмы. Спасибо.
  • Вопрос задан
  • 54 просмотра
Решения вопроса 3
DevMan
@DevMan
пдо здесь ни у чем не уиноват: названия колонок/таблиц не могут быть плейсхолдерами, только параметры.
Ответ написан
alexey-m-ukolov
@alexey-m-ukolov Куратор тега PHP
Таблицы и колонки нельзя биндить, их нужно указывать явно в тексте запроса.
Ответ написан
Комментировать
FanatPHP
@FanatPHP
Чебуратор тега РНР
Все верно объснили, но никто не написал, как сделать правильно.
Единственным правильным вариантом использования такой функции будет что-то вроде
function getСolumn( $db, $sql, $params = null) {
    $stmnt = $db->prepare( $sql );
    $stmnt->execute($params);
    return $stmnt->fetchAll( PDO::FETCH_COLUMN);
}
print_r( getColumn( $db, 'SELECT category_name FROM categories') );

Или, в еще более генерализованном варианте,
function query( $db, $sql, $params = null) {
    $stmt = $db->prepare( $sql );
    $stmt->execute($params);
    return $stmt;
}
print_r( query( $db, 'SELECT category_name FROM categories')->fetchAll( PDO::FETCH_COLUMN) );


Я настоятельно не рекомендую заниматься экономией на спичках и пытаться скостить себе написание двух SQL операторов. Мало того, что надпись вида getNames( $db, 'categories', 'category_name' ) сторонний человек не поймет без того чтобы заглянуть в описание функции, мало того, что такое написание вызывает ложное чувство безопасности. Но, главное, запрос без параметров очень редко когда бывает нужен, и такая функция большую часть времени просто не будет использоваться.

SQL - это гениальное изобретение, позволяющее буквально в нескольких словах описать сложнейшие операции с данными. Не надо считать себя самым умным и пытаться "улучшить" SQL, сократив его до лексикона Эллочки-людоедки.

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

Не нужно вообще ловить исключения PDO. Они прекрасно могут сообщить о себе сами.
function dbConnect($dsn, $user, $password) {
    return new PDO( $dsn, $user, $password, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION] );
}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы
YCLIENTS Москва
от 200 000 до 350 000 ₽
Ведисофт Екатеринбург
от 25 000 ₽
ИТЦ Аусферр Магнитогорск
от 100 000 до 160 000 ₽