Pull to refresh

Comments 54

А типа в плюсах бросание исключений в деструкторе к чему-то хорошему приводит. Как минимум потеря памяти. Если такое предусматривается, то явно ошибка архитектуры
Я привел пример когда эксепшен бросается неявно.
Аналог в плюсах — обращение к нулевой памяти в деструкторе. Мы кидали исключение? нет. Но мы можем его поймать и увидеть, что тут где то указатель занулился. А не «Unknown:0»
Вы не можете сделать из пхп плюсы, он не предназначен для этого.
я и не пытался. я просто решаю задачи в ООП стаил. деструкторы по мне это удобная штука управления обьектами. так же как и конструкторы.
я не возмущаюсь что там нет копирования, типизации, перегрузок и прочих радостей жизни.
но дядя сказал «поддерживаю», значит должен поддерживать. а внезапный конфуз «поддерживаю, но не так как велит разум» смущает.
(Если вы только про Unknown:0, меня бы вполне устроило «exceptions in destructors not allowed (object BlaBla)»)
К примеру меня убивают строки «Destructor order is not guaranteed to be deterministic.»
Последовательность деструкторов в одной области видимости действительно неявна.
Если вы с плюсов слазите в пхп, то вас ещё очень долго будет раздражать недопиленность последнего. Я сам пишу на обоих одновременно и как-то свыкся с областью задач каждого, и с возможностями.
это меня не задевает. меня выводит из равновесие нежелание разработчиков признать свои ошибки и исправить код.
а то получается как в том анекдоте. «у вас не работает такая то кнопка если открыть фаил с таким расширением.» в следующем патче приходит ответ «поддержка вот такой функции для файлов такого типа приостановлена»
Деструкторы к ООП имеют довольно относительное отношение.

Вообще, деструктор как явление относится к языкам с ручным управлением памятью. В языках с автоматическим управлением памятью (сборщиком мусора) деструкторы отсутствуют как класс — вместо них при необходимости применяются финализаторы.

Если бы вы писали на любом языке со сборщиком мусора (C# или Java), то знали бы — выбрасывание исключений в финализаторе ни к чему хорошему не приводят. В C# такое телодвижение вызывает брутальный краш программы, так как фактически исключение выкидывается в поток сборщика мусора.

Не надо перекладывать ваш 4-летний опыт программирования на С++ на другие языки.
Понятие «деструктор» не имеет отношения к сборке мусора, это отдельная концепция вообще-то.
Не самая лучшая тема для первого и последнего поста на Хабре.
последнее время читал блог пхп, и поражался насколько простые вещи пишут. что то вроде «использование классов», «наследование». подумал почему бы нет. к тому же подобной информации нигде не найти, дак может кому то пригодится. ведь поведение движка совершенно неадекватное и нелогичное.
и самое обидное исправления затрагивают только документацию.
Насколько помню поведение с перекрестными ссылками исправили в последних версиях PHP. Сам не пробовал проверять, не было необходимости, но разработчики уверяют что да.

Что касается деструкторов — у меня вот ни разу такой эксепшен не вываливался. Единственное что приходит на ум — закрытие хэндлеров на запись в файл, или каких других ресурсов. Больше мне не приходилось сталкиваться с необходимостью их использования. Для чистки памяти они не целесообразны. Для отрабатывания какого-либо кода по завершению исполнения, как это иногда любят делать, тоже. Для этого есть register_shutdown_function. Словом, проблема возможно и есть, но не критичная.
ИМХО очень субьективно. Мне, например, было интересно. Сам пару лет назад натыкался на странное поведение деструктора в PHP, но забил и решил задачу иначе, не было времени копать. Теперь стало понятнее.
всем хорошо известно, что будущее за интерпретатором кобола.
каких стандартных конструкций нужно в c++ чтобы он был ориентирован на веб?
была попытка заточить плюсы под веб tntnet.org, посмотрите.
Про
$earth = new world();
$vasya = new human($earth);
— напишите минимальный код, воспроизводящий проблему. Деструктор $earth ну никак не должен вызываться раньше деструктора $vasya, т.к. счетчик ссылок на объект не становится равным нулю до смерти $vasya. Скорее всего, где-то в доугом месте у вас проблема.

Что касается остального, то это не столько проблемы php, сколько проблемы самой идеологии синхронных деструкторов (увы). Если вы в c++ начнете активно использовать shared_ptr (а лучше бы начать), будет почти то же самое.
Смотрите. Есть обьект SCREEN. Это подсистема страниц экранов (аля дос). Отдельно рисуется лог (который дампится в фаил), отдельно то что видет юзер, отдельно скажем каллстек и отдельно команды js библиотеке, которые в конце переводятся в json и дампятся в какой нибудь див. Надеюсь назначение ясно.
Все поля protected, все паблик методы — static. Экземпляры создаются (детьми), для какой то определенной цели. В коде деструктора ничего не зануляется, он пустой.
— Пусть есть некоторый обьект $DUMMY. В деструкторе он хочет сделать что то типа SCREEN::AddToErrorLog($text);
— $ScreenErrorLog был создан раньше $Dummy.
Таким образом ссылок на экран нет. Но он был создан раньше, и нигде не удалялся. Значит логично предположить что он существует. Увы, нет. Скрипт выдает что то типа «ребенок уже был завершен, все что должен был вывел куда нужно, и теперь только в режиме рид онли».
Может быть немного коряво, но суть, что обьекты должны удаляться в порядке обратном созданию, до тех пор пока ссылки не требуют обратного. А в пхп они удаляются в прямом порядке.
В случае автоматического управления памятью объекты должны удаляться в том порядке, в котором им прикажет сборщик мусора.

Мне не известно ни одного языка со сборщиком мусора, который гарантирует хоть какой-нибудь порядок удаления объектов.
Значит логично предположить что он существует.

схчегобы?
уничтожать объекты по моему логично только когда исключается возможность работы с ними. это происходит только во время покидания области видимости.
я объект не уничтожал, и хочу с ним работать. обьект пропал. схчегобы?
нельзя считать что находясь в деструкторе вы находитесь в области видимости. это состояние гдето между )
хорошо, а что вы скажете на
function bla_bla()
{
$a = new dummy();
{ // можно пустые оставить, можно if, for etc.
$b = new dummy();
}
}

В каком порядке по вашему логично их удалять?
Мне кажется очевидным что сначала следует отчистить $b, затем $a.
Вы можете проверить, в пхп это не так.
насколько я помню механизм работы сборщика мусора, он не мониторит постоянно изменения. Он делает это только тогда, когда надо выделить еще памяти, а свободной уже мало при данном объеме. В итоге гарантировать что из кучи выберут именно тот или иной объект в таком-то порядке нельзя. Выберут тот объект, на который больше не ссылается ни одна переменная, и конечно же, тот, что не вызовет большой фрагментации. Хотя насчет последнего я могу быть не прав, дано дело было.
Вы бы почитали вначале про алгоритм сбора мусора со счетчиком ссылок (а еще лучше — конкретно про php-шный), а то вам все время что-то неправильное кажется.
Это вам кажется логичным, а алгоритмам сборщика мусора — нет.

Или приведите пример языка, где garbage collector даёт такие гарантии.
Блоки if/for/while в пхп не являются отдельными областями видимости, поэтому порядок удаления может быть любой
добавлю к пердыдущей мысли — вы ведь не вызывали его явно из области видимости
Это все интересно, конечно. Но вы правда не знаете, что такое «минимальный код, воспроизводящий проблему»? Если не знаете, то это самый главный баг, с него надо начинать, а там и с деструкторами все станет в порядке, уверяю.
Да, и про
$a->ref = $b;
$b->ref = $a;
— не до конца это будет существовать в 5.3, а до момента, когда запустится цикл сборки мусора. Он запустится. Когда именно — зависит от настроек, плюс есть статья на английском, где подробно расписано, как в 5.3 работает сборщик мусора (работает он, кстати, довольно интересно — я такого комбинированного метода ни в одном другом языке не видел).
про сборщик мусора я ничего не слышал. в срочном порядке убежал ознакомиться, может чего откопаю и добавлю в публикацию. спасибо.
Сборщик по умолчанию отключен. В концепции скриптов живущих миллисекунды убирать мусор сразу себе дороже, проще отработав убрать всё, по началу к этому сложно привыкнуть.
Использование деструкторов в языках со сборкой мусора — развлечение для мазохистов.
я уже признал свою ошибку. я не думал что там есть сборщик мусора времени исполнения.
думал что переменные очищаются согласно логике локальных переменных в спп, обьекты когда теряются все ссылки и прочее.
а если смотреть на пхп с этой стороны, то деструкторы не такая плохая вещь.

сейчас даже и не знаю что делать.
В PHP нет деструкторов. Несмотря на то, что они так называются — фактически это финализаторы. Их следует использовать только в случае работы с неуправляемыми ресурсами, такими как файлы, сокеты и их аналоги, для того чтобы гарантировать их освобождение. Использование финализаторов для RAII чревато.

Пользуйтесь другими механизмами.
UFO landed and left these words here
Я не говорю, что RAII не работает. Я говорю, что использование финализаторов для RAII в языках с автоматическим управлением памятью чревато проблемами. Суть проблем описана чуть выше.
UFO landed and left these words here
И я. У меня вся работа с транзакциями построена на raii — создается объект-транзакция и, если вдруг он внезапно уничтожается, транзакция роллбэчится. Незаменимая вещь, когда приходится работать с кодом, который может в любой момент выкинуть исключение.
>> Немного о себе. Я программист С++, опыт 4 года
>> «Зачем нанимать веб-программиста, я ведь и сам неплох. Заодно и язык изучу.»

почему не py, java, rb…

шо за ($php === $WWW)?
так сложилось. почему бы и нет?
как это вообще связанно с сабжем?
сложилось, так сложилось.
так почему сложилось PHP?
> Глобальные переменные (аля сессий) перестают быть валидными, доступ к файловой системе обрубается.

В PHP есть чудесная функция register_shutdown_function(). В ней доступ к файловой системе есть.

Ваша проблема, во-первых, в том, что вы переносите подходы к программированию из одного языка в другой, во-вторых, используете ненадежные конструкции.

Не используйте деструкторы для выполнения какой-либо логики (это не только к PHP относится). Если вам надо отсоединить Васю от мира, обнулить ему карму, и прочее, сделайте явный вызов например $world->detach($vasyaId) или $vasya->detach();

Я не представляю ситуации, где деструкторы *жизненно* неоходимы. Единственное, что я бы в них оставил — это вещи типа assert() (например, убедиться что все важные данные сохранены в БД перед уничтожением объекта).

Вам надо сохранить какой-нибудь кеш на диск перед завершением работы скрипта? Сделайте например вызов App::addShutdownHandler(array($his, 'saveData')) и все будет работать.

Явное всегда лучше неявного. Я сталкивался с логикой в конструкторах, и ничего, кроме негативных эмоций, это не вызывает. Это треш, который невозможно отлаживать.

В Си++, который вы упоминаете, деструкторы тоже предназначены исключительно для освобождения памяти дочерних объектов, а люди, которые туда пихают логику, напрашиваются на канделябр от коллеги-разарботчика.
Ну глупость же.
Зачем мне всегда явно васю от мира откреплять. Пусть это инкапсулируется, а я сделаю просто delete vasya.
Многое повидал, но что бы «деструкторы тоже предназначены исключительно для освобождения памяти дочерних объектов», первый раз.
К примеру дерево где для каждого узла считается количество узлов ниже.
Что мне теперь нельзя в деструкторе сделать parent->ChildDetached(this);?
Обязательно это делать явно? Такой подход мне непонятен.

> В PHP есть чудесная функция register_shutdown_function(). В ней доступ к файловой системе есть.
Ясно что есть возможность извернуться в коде так что бы не наступать на это. Но пахнуть не перестанет.
Я в упор не могу понять что в принципе мне может запрещать писать в файлы, нарушается какая то логика, прадигма, или что?
Я просто хочу сбросить дамп, нельзя, канделябр? Круто.
> Ваша проблема, во-первых, в том, что вы переносите подходы к программированию из одного языка в другой, во-вторых, используете ненадежные конструкции.
К сожалению изза вики «Испытал влияние: Perl, C, C++, Java». Вот и подумалось.
Я ни в коем случае не говорю «мир, подстраивайся под меня». Я надеюсь что те кто пройдет путь подобный мне будет предупрежден, а те кто проходили вспомнят былое вместе.
1. Вы, это, когда баги постите, то используйте версии не двухгодичной давности, а последние.
2. Когда читаете сообщения о багах, то читайте до конца, иногда их открывают заново.
3. Если всё же постите баг, то приводите в пример код, который его воспроизводит, не надо пытаться объяснять «на пальцах».
4. Когда видите баг, возможно кто-то его заметил ранее и стоит его поискать.

P.S. global $_SESSION; — использование такой конструкции это тревожный сигнал.
вы кажется невнимательно читали. я же давал ссылки на bugs.php.net.
Там именно эти баги, и они не исправлены(судя по ответам)
У вас пять пунктов. Ссылки даны только для 3, а не для всех. И ещё. Первый баг, по мнению его создателся, относился к документации, соответственно изменения внесли в документацию. Вот ссылка на сам баг, где он закрыт: https://bugs.php.net/bug.php?id=47143
.
Вот код с ЯВНЫМ исключением в деструкторе. И исключение прекрано ловится! pastebin.com/mhxmQEai Или я чего-то недопонял?
Как раз сейчас пишу файловый логгер, в деструкторе присутствует запись в файл, все прекрасно работает.
аналогично. по крону запускается задачка, создает объект Lock, который в деструкторе удаляет .lock файл — всё работает уже не первый год.
Пост из серии «в PHP родительский конструктор нужно вызывать явно»…
Друзья, у меня вопрос, а что если в деструкторе вызываются методы, которые могут вызвать исключительную ситуацию? Такого не должно быть и они должны быть вызваны явно?
лучше так не делать.
там не должно быть исключений уровня логики. допускаются только фатальные эксепшены, которые делают не более чем запись лог/отправка данных и выключают скрипт.
Sign up to leave a comment.

Articles