PHP PDO :: bindParam () типы данных .. как это работает? - PullRequest
29 голосов
/ 07 мая 2009

Мне интересно, для чего используется объявление типа данных в bindParam() (или bindValue()) для ...

Я имею в виду, я думал, что если я определю целочисленный аргумент (PDO::PARAM_INT), аргумент должен быть преобразован в целое число, что-то вроде

$delete->bindParam(1, $kill, PDO::PARAM_INT);
// should work like
$delete->bindParam(1, (int)$kill);

или, по крайней мере, выдать ошибку, если аргумент не имеет объявленного типа. Но это не тот случай.

Погуглив, я обнаружил, что в архиве php.net:

Привет всем,

В настоящее время я работаю над PDO. Именно так на функцию bindParam (). Третий параметр data_type вроде бы здесь заставить тип значения? Но когда я пытаюсь:

$sql = "INSERT INTO produit (idproduit, nom, marque) VALUES (NULL, :nom, :marque)";
$stmt = $dbh->prepare($sql);
$nom = 'Testarossa'; $marque = 'Ferrari' ;
$stmt->BindValue(':marque',$marque) ;
$stmt->BindParam(':nom',$nom,PDO::PARAM_INT) ;

$stmt->execute(); $nom = '250 GTO' ;
$stmt->execute(); ?>

Я ожидал иметь либо PHP ошибка или интергер в моей базе данных. Но в моей БД у меня есть:

22 Testarossa Ferrari 23 250 GTO Ferrari

Это значит, что если я есть третий параметр или нет. Или же возможно я что-то упустил. Может кто то терпеть меня больше? Или просто может кто-то сказал мне, где я могу найти информацию об этом.

С уважением,

Cyruss

Это точно моя ситуация. Где мои мысли не так?

Ответы [ 4 ]

32 голосов
/ 15 мая 2009

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

   if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_STR && param->max_value_len <= 0 && ! ZVAL_IS_NULL(param->parameter)) {
                if (Z_TYPE_P(param->parameter) == IS_DOUBLE) {
                        char *p;
                        int len = spprintf(&p, 0, "%F", Z_DVAL_P(param->parameter));
                        ZVAL_STRINGL(param->parameter, p, len, 0);
                } else {
                        convert_to_string(param->parameter);
                }
        } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_INT && Z_TYPE_P(param->parameter) == IS_BOOL) {
                convert_to_long(param->parameter);
        } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_BOOL && Z_TYPE_P(param->parameter) == IS_LONG) {
                convert_to_boolean(param->parameter);
        }

Итак, если вы говорите, что это STR (или вообще ничего не говорите, так как это по умолчанию), а внутренний тип ваших данных - double, тогда он превратит его в строку одним методом, если это не double, тогда он преобразует его в строку другим методом.

Если вы скажете, что это int, но на самом деле это bool, тогда он преобразует его в long.

Если вы скажете, что это bool, но на самом деле это число, оно преобразует его в истинное логическое значение.

Это действительно все, что я видел (быстро), глядя на источник stmt, я представляю, как только вы передадите параметры в драйвер, они могут творить дополнительную магию. Итак, я предполагаю, что все, что вы получите, - это немного поработать правильно и много неоднозначности и различий в поведении между водителями.

21 голосов
/ 15 мая 2009

Итак, я решил погрузиться в исходный код PHP, и это то, что я нашел.

static int really_register_bound_param в ext / pdo / pdo_stmt.c в строке 329 версии 5.2.9

if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_STR && param->max_value_len <= 0 && ! ZVAL_IS_NULL(param->parameter)) {
    if (Z_TYPE_P(param->parameter) == IS_DOUBLE) {
        char *p;
        int len = spprintf(&p, 0, "%F", Z_DVAL_P(param->parameter));
        ZVAL_STRINGL(param->parameter, p, len, 0);
    } else {
        convert_to_string(param->parameter);
    }
} else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_INT && Z_TYPE_P(param->parameter) == IS_BOOL) {
    convert_to_long(param->parameter);
} else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_BOOL && Z_TYPE_P(param->parameter) == IS_LONG) {
    convert_to_boolean(param->parameter);
}

Это преобразования, которые PDO выполняет во время привязки.

  • PDO :: PARAM_STR преобразует все, что вы даете, в строку, кроме нуля.
  • PDO :: PARAM_INT конвертирует bools в long
  • PDO :: PARAM_BOOL конвертирует long в bools

Вот и все. Больше ничего не обращено. PDO использует флаги PARAM для форматирования SQL, а не для приведения типов данных.

6 голосов
/ 07 мая 2009

Существует как минимум один эффект, который PDO :: PARAM_INT оказывает на INSERT запросов: логические значения преобразуются в 0 или 1. Как в

$i = true;
$stmt->bindParam(':i', $v, PDO::PARAM_INT);

pdo_stmt.c:

else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_INT && Z_TYPE_P(param->parameter) == IS_BOOL) {
        convert_to_long(param->parameter);
}
3 голосов
/ 15 мая 2009

Я попробовал то же самое с BindValue и получил тот же результат, поэтому поведение, которое вы видите, не ограничивается bindParam.

$stmt->BindValue(':marque', $marque) ;
$stmt->BindValue(':nom', $nom, PDO::PARAM_INT) ;

$stmt->execute();
$nom = '250 GTO';
$stmt->BindValue(':nom', $nom, PDO::PARAM_INT) ;
$stmt->execute(); 
...