Стек ошибок: 3) Fatal error: Exception thrown without a stack frame in Unknown online 0 2) Выкинутое мной исключение 1) odbtp_rollback() expects parameter 1 to be resource, integer given; class.MSSQLDB.php; 175 odbtp_set_attr() expects parameter 3 to be resource, integer given; class.MSSQLDB.php; 176 Поиск причин: По имени файла и номеру строчки нашел метод rollback. Из него залогировал стек вызовов. Получил что rollback вызывается из деструктора. Погуглил по Fatal error - нашел http://bugs.php.net/bug.php?id=33598 Таким образом вырисовывается картина: 1)При окончании работы скрипта вызывается деструктор. 2)Деструктор вызывает rollback. 3)У объекта в переменной $link вместо ресурса соединения находится integer. Строка 175 4)Не удается выполнить действие и выбрасывается исключение Строка 177 5)В деструкторе нельзя выбрасывать исключение => Fatal error Код служебных классов: PHP: <?php abstract class SQLDB { //... public function __destruct(){ $this->rollback(); $this->closeConnection(); } //... PHP: <?php class MSSQLDB extends SQLDB{ //... /** * Производит откат транзакции и включает autocommit. */ public function rollback(){ logVar('s',debug_backtrace()); odbtp_rollback($this->link); //Строчка 175 $temp=odbtp_set_attr(ODB_ATTR_TRANSACTIONS, ODB_TXN_NONE,$this->link); if (!$temp){ throw new SqlException("Ошибка при выставлении параметра транзакций","Ошибка подключения","SET TRANSACTION ISOLATION LEVEL"); } } //... Продолжение поиска причин: Почему сбрасывается соединение с БД? Особенно учитывая ,что эта конструкция пол года нормально работала? Вероятно последние изменения в коде сайта(не в коде служебных классов, его не трогал) то-то нарушили. А старой версии уже нет... (Знаю что дурак). Выхода два: 1) Разобраться с ситуацией. 2) Попытаться вернуться к старому коду и постепенно внести изменения. Пока иду по первому пути. Собираю дополнительные данные Дополнительные данные: Допонение к картине: Судя по собранным логам PHP вызывает деструктор для объекта, который должен был быть уничтожен еще в прошлое обращение к серверу. Далее идентификатор объекта разный в разных браузерах. Если перезапустить браузер идентификатор тоже меняется. Вывод: идентификатор зависит от сессии => я где-то пихаю объект для работы с БД в сессию... И похоже я знаю где. Точно. Вопрос: Нужно ли кому нибудь это рассуждение или лучше удалить тему?
Ну как минимум делать это через сохранение сессии очень не гут, т.к. теряете линк на соединение как минимум. Да ещё скорее всего PHP сам закрывает соединение с базой за вас, что в итоге приводит к тому, что у вас просто нету линка на сессию соединения. ИМХО. Во вторых в PHP нету механизма, который бы уничтожал в правильном порядке все объекты. И это не излечимо без построения архитектуры приложения, которое само за собой подчищает всё и вся в правильном порядке. Я такое реализовал, у меня в точке входа в приложение последней строчкой стоит unset($core), который тригерит исполнение деструктора, ну а он в свою очередь уже берёт список объектов и в правильной последовательности их уничтожает. Фокус в том, что иногда объекты ещё нужно инициализировать в правильном порядке, поетому иногда бывает что приходится некоторые объекты инициализировать раньше, чем их использовать.
мне тоже всегда казалось, что php сам закрывает соединение... не знал, где то читал "В php использовать __destruct приходится редко потому, что он сам прекрасно работает с памятью" не помню как точно написано было
Да я, собственно, уже понял в чем проблема. Именно в том, что объект сериализуется и теряет соединение. Я решил вопрос с помощью __sleep и __wakeup. PHP то конечно закрывает. Строго говоря БД откатывает неподтвержденные транзакции при закрытии соединения, так что и rollback делать не обязательно. Но мне кажется, что за собой все таки надо убирать.
Padaboo насолько я понял, суть не в работе с памятью, а в последовательном поедании змеи с головы, а не с хвоста, ибо иначе как раз валятся эти всякие эксепшоны и эрроы.
Volt(220) Да, __sleep и __wakeup оно самое. Причём я сам недавно их в первый раз заюзал. До этого в голове не укладывалось, куда их применить можно, а тут бац - и задача появилась, вписались идиально 2all Да, проблема именно в последовательности. Если у вас сделаны деструкторы для подчищения за собой, и они пытаются уничтожать другие объекты - вам рано или поздно придётся делать систему ручной обработки порядка уничтожения, потому что когда скрипт закончится и запустятся деструкторы, может оказатся, что какой-то объект уже снесло до того, как вы уничтожили объект, который от него зависит. У меня было такое: в session объекте используется memcache. При уничтожении session (в деструкторе прописано сохраниение данных в memcache и собственно потом очистка самого объекта) объект memcache к тому времени уже убивался и естественно получалась ошибка со всеми вытекающими. Пришлось контролировать уничтожение руками.
PHP: <?php class BL_Session_StorageAdapter_Memcache extends BL_Session_StorageAdapterAbstract { protected $memcache; // ... public function commit() { $this->memcache->store($this->getKey(), $this->data); } public function __desctruct() { $this->options['auto_commit'] && $this->commit(); } } не?