Защо получавам Не мога да предам параметър 2 чрез референтна грешка, когато използвам bindParam с постоянна стойност?

Използвам този код и съм извън разочарованието:

try {
    $dbh = new PDO('mysql:dbname=' . DB . ';host=' . HOST, USER, PASS);
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $dbh->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES 'utf8'");
}
catch(PDOException $e)
{
    ...
}
$stmt = $dbh->prepare('INSERT INTO table(v1, v2, ...) VALUES(:v1, :v2, ...)');
$stmt->bindParam(':v1', PDO::PARAM_NULL); // --> Here's the problem

PDO::PARAM_NULL, null, '', всички те се провалят и извеждат тази грешка:

Фатална грешка: Не може да се предаде параметър 2 чрез препратка в /opt/...


person Nacho    schedule 08.09.2009    source източник


Отговори (9)


Трябва да използвате bindValue, а не bindParam

bindParam приема променлива по референция и не извлича стойност по време на извикване на bindParam. Намерих това в коментар за PHP документите:

bindValue(':param', null, PDO::PARAM_INT);

P.S. Може да се изкушите да направите това bindValue(':param', null, PDO::PARAM_NULL);, но не работи за всички (благодаря на Уил Шейвър за докладването.)

person JasonWoof    schedule 08.09.2009
comment
Не съм сигурен каква е разликата между тези две, но ще проуча някои. Благодаря, и твоят отговор беше страхотен. - person Nacho; 08.09.2009
comment
Мисля, че това може да е по-добър отговор от моя (ако наистина работи) - person Joe Phillips; 04.03.2010
comment
моите тестове на PHP 5.3.8 + Mysql показват, че няма разлика в генерираната заявка между двете. Важната част изглежда е, че предадената стойност е NULL, а не '' или '0' - person Odin; 06.11.2011
comment
Имах проблеми с PDO::PARAM_NULL на MySql 5.1.53, но PDO::PARAM_INT с нулева стойност работи чудесно. - person Will Shaver; 05.12.2011
comment
Один: Мисля, че най-важната част е да се преминат и трите параметъра :). във въпроса на ign той предаваше PDO::PARAM_NULL като стойност, вместо като тип (и изобщо не предаваше тип.) - person JasonWoof; 17.12.2011
comment
FYI: в повечето случаи сте напълно добре да използвате bindValue() над bindParam(); за всичко, не само за стойността NULL. Не мога да се сетя за нито един случай, в който ще трябва да свържете параметъра към препратка към PHP променлива - но това е, което bindParam() прави. - person low_rents; 03.12.2015

Когато използвате bindParam(), трябва да подадете променлива, а не константа. Така че преди този ред трябва да създадете променлива и да я зададете на null

$myNull = null;
$stmt->bindParam(':v1', $myNull, PDO::PARAM_NULL);

Ще получите същото съобщение за грешка, ако опитате:

$stmt->bindParam(':v1', 5, PDO::PARAM_NULL);
person Joe Phillips    schedule 08.09.2009
comment
Разбрахте правилно, току-що осъзнах, че съм го правил преди в моя код, $null = PDO::PARAM_NULL; Благодаря. - person Nacho; 08.09.2009
comment
По-добре е да използвате bindValue() в този случай, ако все пак ще правите контейнери. bindParam() първоначално е предназначен да изпълни заявка и след това да промени променливите и да изпълни отново, без да обвързва отново параметрите. bindValue() се свързва незабавно, bindParam() само при изпълнение. - person Hugo Zink; 07.10.2015
comment
Открих, че null трябва да е малка буква в реда $myNull = null. $myNull = NULL НЕ работи. - person raphael75; 28.11.2017

При използване на INTEGER колони (които могат да бъдат NULL) в MySQL, PDO има известно (за мен) неочаквано поведение.

Ако използвате $stmt->execute(Array), трябва да посочите литерала NULL и не можете да дадете NULL чрез препратка към променлива. Така че това няма да работи:

// $val is sometimes null, but sometimes an integer
$stmt->execute(array(
    ':param' => $val
));
// will cause the error 'incorrect integer value' when $val == null

Но това ще свърши работа:

// $val again is sometimes null, but sometimes an integer
$stmt->execute(array(
    ':param' => isset($val) ? $val : null
));
// no errors, inserts NULL when $val == null, inserts the integer otherwise

Опитах това на MySQL 5.5.15 с PHP 5.4.1

person ChrisF    schedule 23.12.2012
comment
$stmt-›execute(array( ':param' =› !empty($val) ? $val : null )); Използвайте !empty, защото за празен низ бихте искали също да зададете null в базата данни - person Shehzad Nizamani; 30.06.2017
comment
@ShehzadNizamani Само ако типът на колоната е цяло число, както в неговия пример, да. Но иначе isset() корелира по-добре с NULL. Празен низ също е стойност. - person StanE; 17.11.2017
comment
@ShehzadNizamani какво ще кажете за 0 стойност? empty() ще върне true за него. и вашият код ще съхранява null вместо законна 0 целочислена стойност - person Your Common Sense; 13.02.2021

За тези, които все още имат проблеми (не може да прехвърли параметър 2 чрез препратка), дефинирайте променлива с нулева стойност, а не просто да предадете null към PDO:

bindValue(':param', $n = null, PDO::PARAM_INT);

Надявам се това да помогне.

person Pedro Guglielmo    schedule 24.09.2013

Имах същия проблем и открих, че това решение работи с bindParam:

    bindParam(':param', $myvar = NULL, PDO::PARAM_INT);
person user1719210    schedule 21.04.2015

Ако искате да вмъкнете NULL само когато value е empty или '', но вмъкнете value, когато е налично.

A) Получава данните от формуляра с помощта на метода POST и извиква функцията insert с тези стойности.

insert( $_POST['productId'], // Will be set to NULL if empty    
        $_POST['productName'] ); // Will be to NULL if empty                                

B) Оценява дали дадено поле не е попълнено от потребителя и вмъква NULL, ако случаят е такъв.

public function insert( $productId, $productName )
{ 
    $sql = "INSERT INTO products (  productId, productName ) 
                VALUES ( :productId, :productName )";

    //IMPORTANT: Repace $db with your PDO instance
    $query = $db->prepare($sql); 

    //Works with INT, FLOAT, ETC.
    $query->bindValue(':productId',  !empty($productId)   ? $productId   : NULL, PDO::PARAM_INT); 

    //Works with strings.
    $query->bindValue(':productName',!empty($productName) ? $productName : NULL, PDO::PARAM_STR);   

    $query->execute();      
}

Например, ако потребителят не въведе нищо в полето productName на формуляра, тогава $productName ще бъде SET, но EMPTY. Така че трябва да проверите дали е empty() и ако е, тогава вмъкнете NULL.

Тествано на PHP 5.5.17

Късмет,

person Arian Acosta    schedule 18.10.2014
comment
Или можете да използвате функцията IFNULL() на MySQL в низа на заявката. Подобно на това: $sql = "INSERT INTO products ( productId, productName ), VALUES ( IFNULL(:productId, NULL), IFNULL(:productName, NULL) )"; - person starleaf1; 10.12.2014
comment
Харесва ми чистотата на вашето решение. Току-що го тествах, но за съжаление той вмъква празни низове вместо NULL, когато потребителят не пише нищо на входа. Това е просто въпрос на предпочитание, но аз предпочитам NULL вместо празни низове. - person Arian Acosta; 15.12.2014

Въз основа на другите отговори, но с малко повече яснота как всъщност да използвате това решение.

Ако например имате празен низ за времева стойност, но искате да го запишете като нула:

  if($endtime == ""){
    $db->bind(":endtime",$endtime=NULL,PDO::PARAM_STR);
  }else{
    $db->bind("endtime",$endtime);
  }

Забележете, че за времеви стойности бихте използвали PARAM_STR, тъй като времената се съхраняват като низове.

person Vincent    schedule 10.03.2020

В моя случай използвам:

  • SQLite,

  • подготвени изрази с контейнери за обработка на неизвестен брой полета,

  • AJAX заявка, изпратена от потребител, където всичко е низ и няма такова нещо като NULL стойност и

  • Отчаяно трябва да вмъкна NULLs, тъй като това не нарушава ограниченията за чужд ключ (приемлива стойност).

Да предположим, че сега потребителят изпраща с публикация: $_POST[field1] със стойност value1, която може да бъде празен низ "" или "null" или "NULL".

Първо правя изявлението:

$stmt = $this->dbh->prepare("INSERT INTO $table ({$sColumns}) VALUES ({$sValues})");

където {$sColumns} е sth като field1, field2, ... и {$sValues} са моите заместители ?, ?, ....

След това събирам моите $_POST данни, свързани с имената на колоните в масив $values и заменям с NULLs:

  for($i = 0; $i < \count($values); $i++)
     if((\strtolower($values[$i]) == 'null') || ($values[$i] == ''))
        $values[$i] = null;

Сега мога да изпълня:

$stmt->execute($values);

и сред другите заобикалящи ограничения на външния ключ.

Ако от друга страна, празен низ има повече смисъл, тогава трябва да проверите дали това поле е част от външен ключ или не (по-сложно).

person centurian    schedule 29.11.2018

Опитайте тази.

$stmt->bindValue(':v1', null, PDO::PARAM_NULL); // --> insert null
person hector teran    schedule 04.05.2017
comment
Преди да се опитате да отговорите на такъв стар въпрос, първо трябва да прочетете други отговори. Може би вече е отговорено. - person Your Common Sense; 04.05.2017