Я видел много статей, используя двоеточия (:) перед именованными параметрами при использовании PDO, и пару, которая не использует двоеточие. Я бы так же быстро не использовал двоеточие, просто потому, что это одно нажатие клавиши и немного легче читать.
Кажется, он работает отлично для меня, но мне любопытно, есть ли что-то важное, что мне не хватает, когда дело доходит до использования двоеточий?
Например, это работает отлично:
function insertRecord ($conn, $column1, $comumn2) { try { $insertRecord = $conn->prepare('INSERT INTO Table1 (column1, column2) VALUES(:column1, :column2)'); $insertRecord->execute(array( 'column1' => $column1, 'column2' => $column2 )); } catch(PDOException $e) { echo $e->getMessage(); } }
В отличие от большинства разработчиков, использующих это, что также работает:
function insertRecord ($conn, $column1, $comumn2) { try { $insertRecord = $conn->prepare('INSERT INTO Table1 (column1, column2) VALUES(:column1, :column2)'); $insertRecord->execute(array( ':column1' => $column1, ':column2' => $column2 )); } catch(PDOException $e) { echo $e->getMessage(); } }
Обратите внимание на двоеточия в параметрах инструкции execute
.
Я хотел бы понять, для чего нужны двоеточия.
В операторе SQL требуются колонии, чтобы указать, какие идентификаторы являются заполнителями.
bindParam()
вызовов execute()
или bindParam()
являются необязательными. Документация указывает их, но реализация достаточно умна, чтобы понять, что вы имеете в виду, если вы их оставите (что еще вы могли иметь в виду?).
TL; DR Нет, вы ничего не пропустили. Вы должны использовать двоеточия (:) с именованными заполнителями в строке SQL, но они не требуются при выполнении оператора или параметров привязки. PHP выведет :
если вы оставите это в этом контексте (см. Второй раздел ниже для объяснения и доказательства из исходного кода для самого интерпретатора PHP).
Другими словами, это приемлемо:
$insertRecord = $conn->prepare('INSERT INTO Table1 (column1, column2) VALUES(:column1, :column2)'); // ^ ^ note the colons
но это не так, потому что имена заполнителей неоднозначны и похожи на имена столбцов (или других):
$insertRecord = $conn->prepare('INSERT INTO Table1 (column1, column2) VALUES(column1, column2)'); // ^ ^ no colons
Напротив, двоеточия являются необязательными при использовании PDOStatement::bindParam()
или PDOStatement::execute()
. Обе эти работы в основном идентичны: *
$insertRecord->execute(array( ':column1' => $column1, ':column2' => $column2 )); // or $insertRecord->execute(array( 'column1' => $column1, 'column2' => $column2 ));
Почему это так работает? Ну, для этого нам нужно попасть в исходный код c -языка для самого PHP. Чтобы сохранить текущее значение, я использовал последний источник из github (PHP 7), но тот же базовый анализ применяется к более ранним версиям.
Язык PHP ожидает, что именованные заполнители будут иметь двоеточие в SQL , как указано в документах. И документация для PDOStatement::bindParam()
указывает, что параметр должен иметь вид :name
когда вы привязываете параметр к заполнителю . Но это не совсем так, по следующим причинам.
Там нет риска двусмысленности, когда приходит время связывать параметры или выполнять оператор, потому что SQL-заполнитель должен иметь один и только один двоеточие. Это означает, что интерпретатор PHP может сделать критическое предположение и сделать это безопасно. Если вы посмотрите на pdo_sql_parser.c
в исходном коде PHP, особенно в строке 90 , вы можете увидеть действительный список символов в заполнителе, а именно буквенные символы (цифры и буквы), символы подчеркивания и двоеточие. Следуя логике кода в этом файле, немного сложно и трудно объяснить здесь – я, к сожалению, говорю, что это связано с множеством goto
но короткая версия заключается в том, что только первый символ может быть двоеточием.
Проще говоря :name
является допустимым заполнителем в SQL, но name
и ::name
не являются.
Это означает, что парсер может с уверенностью предположить, что к моменту, когда вы получите bindParam()
или execute()
, параметр с именем name
должен быть действительно :name
. То есть, он может просто добавить a :
перед остальным именем параметра. Фактически, это именно то, что он делает, в pdo_stmt.c
, начиная со строки 362 :
if (param->name) { if (is_param && param->name[0] != ':') { char *temp = emalloc(++param->namelen + 1); temp[0] = ':'; memmove(temp+1, param->name, param->namelen); param->name = temp; } else { param->name = estrndup(param->name, param->namelen); } }
Что это делает, в слегка упрощенном псевдокоде:
if the parameter has a name then if the parameter name does not start with ':' then allocate a new string, 1 character larger than the current name add ':' at the start of that string copy over the rest of the name to the new string replace the old string with the new string else call estrndup, which basically just copies the string as-is (see https://github.com/php/php-src/blob/1c295d4a9ac78fcc2f77d6695987598bb7abcb83/Zend/zend_alloc.h#L173)
Таким образом, name
(в контексте bindParam()
или execute()
) становится :name
, которое соответствует нашему SQL, и PDO совершенно счастлив.
Технически, любой способ работает, поэтому вы можете сказать, что это вопрос предпочтения. Но в случае, если это не очевидно, это плохо документировано. Мне пришлось очень глубоко погрузиться в исходный код, чтобы понять это, и это теоретически может измениться в любое время. Для обеспечения согласованности, удобочитаемости и упрощения поиска в среде IDE используйте двоеточие.
* Я говорю, что они работают «в основном» идентично, потому что вышеприведенный код c накладывает крайне незначительный штраф за уход из двоеточия. Он должен выделять больше памяти, строить новую строку и заменять старую строку. Тем не менее, это наказание в наносекундном диапазоне для имени типа :name
. Это может стать измеримым, если вы склонны давать свои параметры очень длинным (например, 64 Кб) именам, и у вас их много, и в этом случае у вас есть другие проблемы … Наверное, ничто из этого не имеет значения, во всяком случае, поскольку двоеточие добавляет крайне небольшое наказание во времени, чтобы читать и разбирать файл, поэтому эти два сверхмалых штрафа могут даже компенсироваться. Если вы беспокоитесь о производительности на этом уровне, у вас гораздо более холодные проблемы, чтобы вы не спали по ночам, чем остальные. Кроме того, в этот момент вы, вероятно, должны создать свой webapp в чистом ассемблере. </ Sarcasm>
Документация для bindParam запрашивает двоеточие. Даже если это работает без, я бы не стал нам этого, потому что вы не можете быть уверены, что если он также работает со следующей версией на php.
Это личное предпочтение, некоторые полагают, что это однозначно, но я не вижу в этом ничего двусмысленного. Это параметр.
Так же, как некоторые люди любят делать нумерованные параметры (используя?) Вместо названных параметров.
Да, это абсолютно безопасно, но также есть возможность быть небезопасной. Вы можете спросить, как такой контраст существует одновременно? Ну, в программировании мира ИМХО нет окончательности.
Поскольку PHP 5.1 PDO поставляется с PHP как встроенная функция, с этого времени добавление двоеточия к не имеющему двоеточие с именем параметр отсутствует . Сказав, что через 10 лет это не будет проблемой для сообщества PHP, чтобы отказаться от него. Почему действительно?
Он не документирован. На самом деле, хорошие ребята из сообщества PHP знали о случайных простых ошибках своих товарищей и реализовывали такую головную боль, чтобы страстно заботиться о своей вероятной путанице за кадром, и она нигде не документирована, потому что вы имеете дело с заполнителями.
Заполнитель в основном различим со специальным символом (символами) / форматом, например, как вы printf
заполнители printf
%d %s
а не ds
. Вам нужно только правильно следовать формату заполнителя и не пытаться отбросить его на колени PHP.
Когда он не задокументирован, у него есть – даже эпсилон – шанс быть пропущенным.
В официальной документации показан только синтаксис с двоеточиями:
$insertRecord->execute(array( ':column1' => $column1, ':column2' => $column2 ));
Кроме того, внутренне (исходный код PDO), если отсутствует ведущий двоеточие, он будет добавлен автоматически.
Поэтому вы должны использовать синтаксис WITH colons, чтобы быть уверенным.