За последние 24 часа нас посетили 88108 программистов и 3017 роботов. Сейчас ищут 1372 программиста ...

Вызов деструктора для удаленного объекта. Почему?

Тема в разделе "Прочие вопросы по PHP", создана пользователем Volt(220), 14 июл 2010.

  1. Volt(220)

    Volt(220) Активный пользователь

    С нами с:
    11 июн 2009
    Сообщения:
    1.640
    Симпатии:
    1
    Стек ошибок:
    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:
    1. <?php
    2. abstract class SQLDB {
    3. //...
    4.     public function __destruct(){
    5.         $this->rollback();
    6.         $this->closeConnection();
    7.     }
    8. //...
    PHP:
    1. <?php
    2. class MSSQLDB extends SQLDB{
    3. //...
    4.     /**
    5.      * Производит откат транзакции и включает autocommit.
    6.      */
    7.     public function rollback(){
    8.         logVar('s',debug_backtrace());
    9.         odbtp_rollback($this->link); //Строчка 175
    10.         $temp=odbtp_set_attr(ODB_ATTR_TRANSACTIONS, ODB_TXN_NONE,$this->link);
    11.         if (!$temp){
    12.             throw new SqlException("Ошибка при выставлении параметра транзакций","Ошибка подключения","SET TRANSACTION ISOLATION LEVEL");
    13.         }
    14.     }
    15. //...
    Продолжение поиска причин:
    Почему сбрасывается соединение с БД? Особенно учитывая ,что эта конструкция пол года нормально работала?
    Вероятно последние изменения в коде сайта(не в коде служебных классов, его не трогал) то-то нарушили. А старой версии уже нет... (Знаю что дурак).
    Выхода два:
    1) Разобраться с ситуацией.
    2) Попытаться вернуться к старому коду и постепенно внести изменения.
    Пока иду по первому пути. Собираю дополнительные данные

    Дополнительные данные:
    Допонение к картине:
    Судя по собранным логам PHP вызывает деструктор для объекта, который должен был быть уничтожен еще в прошлое обращение к серверу.
    Далее идентификатор объекта разный в разных браузерах. Если перезапустить браузер идентификатор тоже меняется. Вывод: идентификатор зависит от сессии => я где-то пихаю объект для работы с БД в сессию... И похоже я знаю где.

    Точно.

    Вопрос:
    Нужно ли кому нибудь это рассуждение или лучше удалить тему?
     
  2. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    Ну как минимум делать это через сохранение сессии очень не гут, т.к. теряете линк на соединение как минимум. Да ещё скорее всего PHP сам закрывает соединение с базой за вас, что в итоге приводит к тому, что у вас просто нету линка на сессию соединения. ИМХО.
    Во вторых в PHP нету механизма, который бы уничтожал в правильном порядке все объекты. И это не излечимо без построения архитектуры приложения, которое само за собой подчищает всё и вся в правильном порядке.
    Я такое реализовал, у меня в точке входа в приложение последней строчкой стоит unset($core), который тригерит исполнение деструктора, ну а он в свою очередь уже берёт список объектов и в правильной последовательности их уничтожает. Фокус в том, что иногда объекты ещё нужно инициализировать в правильном порядке, поетому иногда бывает что приходится некоторые объекты инициализировать раньше, чем их использовать.
     
  3. Padaboo

    Padaboo Старожил
    Команда форума Модератор

    С нами с:
    26 окт 2009
    Сообщения:
    5.242
    Симпатии:
    1
    мне тоже всегда казалось, что php сам закрывает соединение...

    не знал, где то читал "В php использовать __destruct приходится редко потому, что он сам прекрасно работает с памятью"
    не помню как точно написано было
     
  4. Volt(220)

    Volt(220) Активный пользователь

    С нами с:
    11 июн 2009
    Сообщения:
    1.640
    Симпатии:
    1
    Да я, собственно, уже понял в чем проблема. Именно в том, что объект сериализуется и теряет соединение.
    Я решил вопрос с помощью __sleep и __wakeup.

    PHP то конечно закрывает. Строго говоря БД откатывает неподтвержденные транзакции при закрытии соединения, так что и rollback делать не обязательно. Но мне кажется, что за собой все таки надо убирать.
     
  5. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    Padaboo
    насолько я понял, суть не в работе с памятью, а в последовательном поедании змеи с головы, а не с хвоста, ибо иначе как раз валятся эти всякие эксепшоны и эрроы.
     
  6. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    Volt(220)
    Да, __sleep и __wakeup оно самое. Причём я сам недавно их в первый раз заюзал. До этого в голове не укладывалось, куда их применить можно, а тут бац - и задача появилась, вписались идиально :)

    2all
    Да, проблема именно в последовательности. Если у вас сделаны деструкторы для подчищения за собой, и они пытаются уничтожать другие объекты - вам рано или поздно придётся делать систему ручной обработки порядка уничтожения, потому что когда скрипт закончится и запустятся деструкторы, может оказатся, что какой-то объект уже снесло до того, как вы уничтожили объект, который от него зависит.

    У меня было такое: в session объекте используется memcache. При уничтожении session (в деструкторе прописано сохраниение данных в memcache и собственно потом очистка самого объекта) объект memcache к тому времени уже убивался и естественно получалась ошибка со всеми вытекающими. Пришлось контролировать уничтожение руками.
     
  7. Koc

    Koc Активный пользователь

    С нами с:
    3 мар 2008
    Сообщения:
    2.253
    Симпатии:
    0
    Адрес:
    \Ukraine\Dnepropetrovsk
    хм, странно В мемкеш-драйвере сессий есть же ссылка на мемкеш, фигли он первей сессий дохнет?
     
  8. Luge

    Luge Старожил

    С нами с:
    2 фев 2007
    Сообщения:
    4.680
    Симпатии:
    1
    Адрес:
    Минск
    Koc
    там самописный механизм сессий
     
  9. Koc

    Koc Активный пользователь

    С нами с:
    3 мар 2008
    Сообщения:
    2.253
    Симпатии:
    0
    Адрес:
    \Ukraine\Dnepropetrovsk
    PHP:
    1. <?php
    2. class BL_Session_StorageAdapter_Memcache extends BL_Session_StorageAdapterAbstract
    3. {
    4.   protected $memcache;
    5.   // ...
    6.  
    7.   public function commit()
    8.   {
    9.     $this->memcache->store($this->getKey(), $this->data);
    10.   }
    11.  
    12.   public function __desctruct()
    13.   {
    14.     $this->options['auto_commit'] && $this->commit();
    15.   }
    16. }
    не?
     
  10. phpdude

    phpdude Активный пользователь

    С нами с:
    9 июл 2010
    Сообщения:
    697
    Симпатии:
    0
    Koc
    ой блин, опять ты с этим, я уже слово бл не навижу, ибо оно ассоциируется со словом *ля
     
  11. Koc

    Koc Активный пользователь

    С нами с:
    3 мар 2008
    Сообщения:
    2.253
    Симпатии:
    0
    Адрес:
    \Ukraine\Dnepropetrovsk
    все только начинается
     
  12. Luge

    Luge Старожил

    С нами с:
    2 фев 2007
    Сообщения:
    4.680
    Симпатии:
    1
    Адрес:
    Минск
    не знаю во что там уже всё выросло и какие задачи сейчас стоят
     
  13. Koc

    Koc Активный пользователь

    С нами с:
    3 мар 2008
    Сообщения:
    2.253
    Симпатии:
    0
    Адрес:
    \Ukraine\Dnepropetrovsk
    подождем что Псих ответит. Ну не верю я, что пых настолько тупой
     
  14. Padaboo

    Padaboo Старожил
    Команда форума Модератор

    С нами с:
    26 окт 2009
    Сообщения:
    5.242
    Симпатии:
    1
    как это работает, последовательность создания объектов отслеживается, сама? как это реализовано?