Я повторно использую переменную для хранения двух разных инструкций mysql PDO:
$stmt=$dbh->prepare("SELECT ...."); $stmt->execute(); $stmt=$dbh->prepare("UPDATE ...."); //crash here: //*** Error in `/opt/lampp/bin/httpd': free(): invalid pointer: 0xf4a028dc *** //*** Error in `/opt/lampp/bin/httpd': free(): invalid pointer: 0xf4a028dc *** //[Mon Jun 03 19:53:48.691674 2013] [core:notice] [pid 20249] AH00052: child pid 25933 exit //signal Aborted (6) //[Mon Jun 03 19:53:48.691727 2013] [core:notice] [pid 20249] AH00052: child pid 25952 exit //signal Aborted (6)
но если вместо этого я использую $ stmt2 = $ dbh-> prepare ("UPDATE …."); ничего странного не происходит, и состояние исполняется в порядке. Это также идет без проблем, если я позволю подготовить эмуляцию:
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES,true);
Я пробовал $stmt->closeCursor()
после выполнения первого оператора, а также unset($stmt)
(а также оба из них), производя тот же самый сбой. Я использую PHP 5.4.7. Почему это происходит? Это ошибка или действительно странная функция?
[UPDATE] Я переключился с xampp на OpenSUSE 12.3 по умолчанию Apache (2.2.22) и PHP (5.3.17) и по-прежнему получал ту же ошибку, но более подробный журнал дампа: http://paste2.org/d0BtdOHI
[ОБНОВЛЕНИЕ 2] Я также подтвердил, что это происходит при использовании MySQL 5.5.27 вместо MariaDB 5.5.29 в качестве сервера, поэтому он определенно подходит к моему сценарию и в значительной степени универсален (попробуйте также виртуальную машину centos на всякий случай это проблема, связанная с glibc из моего дистрибутива …), что происходит с разными версиями apache, mysql и php, но до сих пор не имеет понятия о том, что может быть причиной …
[UPDATE 3] Ну, похоже, CentOS 6.4 гораздо приятнее об этом и позволяет запускать мой скрипт без каких-либо проблем, и поскольку это то, что я использую на производстве, я думаю, что не о чем беспокоиться. В любом случае, мне бы очень хотелось узнать, что здесь происходит …
Я прошу прощения за это последнее обновление, но у меня была аналогичная проблема с PDO (Sybase), и я могу подтвердить, что следует избегать повторного использования переменных оператора без отмены или установки нулевого значения.
В PHP, когда мы перезаписываем значение переменной, сначала создается новая переменная, и только после этого она заменяет и уничтожает старое значение. В большинстве случаев это не проблема (за исключением того, что вы тратите вдвое больше памяти на выделение одной переменной), но с операторами она совершенно другая, поскольку она не закрывает первый оператор или курсор при создании второго, а некоторые базы данных драйверы не обрабатывают множество операторов в одном и том же соединении PDO.
В зависимости от используемого драйвера PDOStatement::closeCursor()
может не закрыть инструкцию, поэтому проблема сохраняется (по адресу http://www.php.net/manual/en/pdostatement.closecursor.php мы видим, что это зависит от драйвера, в противном случае он будет использовать PDO по умолчанию, который не закрывает операторы).
Таким образом, в этом случае unset()
между PDO::prepare()
делает всю разницу:
$stmt=$dbh->prepare("SELECT ...."); $stmt->execute(); unset($stmt); // or $stmt = null; --> statement is destroyed at PDO $stmt=$dbh->prepare("UPDATE ....");
с$stmt=$dbh->prepare("SELECT ...."); $stmt->execute(); unset($stmt); // or $stmt = null; --> statement is destroyed at PDO $stmt=$dbh->prepare("UPDATE ....");