- Saved searches
- Use saved searches to filter your results more quickly
- [HttpClient] Uncatchable fatal error on class destruction #31187
- [HttpClient] Uncatchable fatal error on class destruction #31187
- Comments
- Original Code :
- Error from Log :
- initiated into ResponseTrait
- initiated into ErrorChunk
- PHP не любит деструкторы
- Php destruct fatal error
- Patches
- Pull Requests
- History
Saved searches
Use saved searches to filter your results more quickly
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[HttpClient] Uncatchable fatal error on class destruction #31187
[HttpClient] Uncatchable fatal error on class destruction #31187
Comments
Description
I use http-client in multimode, around with 20 parallel threads, around 1/10000 request running into a fatal error which is triggered by CurlResponse __destruct()
In __destruct() , $this->doDestruct() is called, which can throw error with $this->checkStatusCode();
How to reproduce
No idea. :/
The text was updated successfully, but these errors were encountered:
Finally, error was catchable. but I don’t think this behavior was intended when we use the client in multi mode.
Original Code :
/** @var \Symfony\Component\HttpClient\Response\CurlResponse $response */ foreach ($client->stream($responses) as $response => $chunk) < $info = unserialize($response->getInfo()['user_data']); try < $isLast = $chunk->isLast(); if ($isLast === true) < $body = $response->getContent(); > else < usleep(50); > > catch (Exception $e) < $body = ''; $isLast = true; .... > if ($isLast === true) < .... > >
Error from Log :
initiated into ResponseTrait
PHP Fatal error: Uncaught Symfony\\Component\\HttpClient\\Exception\\ServerException: HTTP/1.1 502 Bad Gatewa returned for URL "http://. ". in /home/algoadm/public_html/admin/composer/vendor/symfony/http-client/Response/ResponseTrait.php:211\nStack trace: #0 /home/algoadm/public_html/admin/composer/vendor/symfony/http-client/Response/ResponseTrait.php(231): Symfony\\Component\\HttpClient\\Response\\CurlResponse->checkStatusCode() #1 /home/algoadm/public_html/admin/composer/vendor/symfony/http-client/Response/CurlResponse.php(169): Symfony\\Component\\HttpClient\\Response\\CurlResponse->doDestruct() #2 /home/algoadm/public_html/admin/script/class/update_vol_collection_manager.class.php(198): Symfony\\Component\\HttpClient\\Response\\CurlResponse->__destruct() #3 /home/algoadm/public_html/admin/script/class/update_ in /home/algoadm/public_html/admin/composer/vendor/symfony/http-client/Response/ResponseTrait.php on line 211
initiated into ErrorChunk
PHP Fatal error: Uncaught Symfony\\Component\\HttpClient\\Exception\\TransportException: Reading from the response stream reached the inactivity timeout. in /home/algoadm/public_html/admin/composer/vendor/symfony/http-client/Chunk/ErrorChunk.php:105\nStack trace: #0 /home/algoadm/public_html/admin/composer/vendor/symfony/http-client/Response/CurlResponse.php(111): Symfony\\Component\\HttpClient\\Chunk\\ErrorChunk->__destruct()\n#1 /home/algoadm/public_html/admin/composer/vendor/symfony/http-client/Response/ResponseTrait.php(229): Symfony\\Component\\HttpClient\\Response\\CurlResponse::Symfony\\Component\\HttpClient\\Response\\(Object(Symfony\\Component\\HttpClient\\Response\\CurlResponse)) #2 /home/algoadm/public_html/admin/composer/vendor/symfony/http-client/Response/CurlResponse.php(169): Symfony\\Component\\HttpClient\\Response\\CurlResponse->doDestruct() #3 /home/algoadm/public_html/admin/script/class/update_vol_collection_manager.class.php(198): Symfony\\Component\\HttpClient\\Response\\CurlResponse->__destruct() #4 /home/algoadm/public_html in /home/algoadm/public_html/admin/composer/vendor/symfony/http-client/Chunk/ErrorChunk.php on line 105
I think the error is thrown only if there is a problem in the last response or into the last chunk
The solution I found, is add below code before the end of my class to deconstruct «manually» each class and catch error :
try < if (isset($response))< $response->__destruct(); > if (isset($chunk) && $chunk instanceof \Symfony\Component\HttpClient\Chunk\ErrorChunk) < $chunk->__destruct(); > > catch (Throwable $e)
PHP не любит деструкторы
Столько воды утекло с тех пор как ПХП провозгласил себя ООП языком. Мне не удалось уточнить когда именно, но «On July 13, 2004, PHP 5 was released, powered by the new Zend Engine II. PHP 5 included new features such as improved support for object-oriented programming».
Т.е теоретически уже тогда появились конструкторы и деструкторы. Сам пользуюсь версией 5.3.2, но диву даюсь что он вытворяет.
Немного о себе. Я программист С++, опыт 4 года. Специализация — компьютерная графика и работа с сетью. А именно создание сетевых игр. Но таким играм нужен сервер, а серверу база игроков. А игроки хотят еще и сайт. «Зачем нанимать веб-программиста, я ведь и сам неплох. Заодно и язык изучу.»
Так я думал пол года назад, но до сих пор не могу понять!
Классическое
Думаю многие кто работал с деструкторами однажды столкнулся:
PHP Fatal error: Exception thrown without a stack frame in Unknown on line 0
Первая реакция — недоумение. Вторая матная. И ведь впихивание exit() везде не дает результата, ведь догадка о том что эксепшен в деструкторе приходит далеко не сразу, а если он происходит, то скорее всего кодовая база значительная.
Ответ c bugs.php.net/bug.php?id=33598
sniper@php.net:
Throwing exceptions in __desctruct() is not allowed.
Should be documented..
vrana@php.net:
Thank you for the report, and for helping us make our documentation better.
«Attempting to throw an exception from a desctructor causes a fatal error.»
Весело? Лично мне не очень.
Воспроизводится ошибка с неявным исключением очень просто.
class a
// .
public function __destruct()
global $_SESSION;
$_SESSION = «Some information»;
>
>
$dummy = new a();
^Примечание, явные исключения иногда работают верно. Буду ставить эксперементы что влияет.
Реверсный порядок очистки
Пусть в некоторой области видимости(глобальной и неочень) у нас следующий код:
$earth = new world();
$vasya = new human($earth);
Соответственно в коде конструктора человека идет его пришпандоривание к миру. (Предполагается что без мира вася существовать не будет, отбросим философию, нам проект скорее закрыть.)
Ну а в коде деструктора вася лежит аля $this->my_world->RemoveHumanFromWorld($this), в котором вызываются RemoveAllMyStuff, CalculateKarma и прочее. (Предположим у нас в мире не хранится ссылка на васю, так как это не требовалось в рамках задачи)
Что делает пхп при выходе из области видимости? Уничтожает мир и падает с ошибкой «Fatal error: Call to a member function RemoveHumanFromWorld() on a non-object in /home/god/my_projects/earth/creatures/reasonable/homo_sapiens.php on line 1956».
(Поэтому кстати мир был написан на С++, ведь богу не нужно что бы он запускался на любой вселенной. Виртуальный космос с сборщиком мусора. Ха Ха.)
Ответ с bugs.php.net/bug.php?id=36759
dmitry@php.net
Fixed in CVS HEAD and PHP_5_2.
Найти бы этого дмитрия и ткнуть носом как в той картинке. Не знаю как там в последних версиях, пока не обновляюсь, но в 5.3 актуально.
Завершение скрипта — исключительная ситуация
Ох, про это столько можно писать. Глобальные переменные (аля сессий) перестают быть валидными, доступ к файловой системе обрубается. И вообще как я понимаю корректная работа скрипта не гарантируется. Так что не дай бог вам выполнять что то в деструкторе глобального обьекта…
Но это опустим. В документации пхп 5.1 и ранее (строфу и стих не найду) сказано: «The destructor method will be called as soon as there are no other references to a particular object», что в принципе логично для языка без строгого требования конструкции delete (лат. unset).
После баг репорта bugs.php.net/bug.php?id=38572
Документация изменилась «The destructor method will be called as soon as there are no other references to a particular object, or in any order during the shutdown sequence»
Удобно? По мне — не очень.
Только прямые ссылки
Пусть согласно логике языка обьект $a должен удалиться раньше $b.
Но пусть в обьекте $b хранится ссылка на поле $a->some_data.
Тогда по логике обьект $b должен удалиться раньше. Увы, в пхп не так. Подобной баги я не нашел, но ситуация специфическая(и не побоюсь слова исключительная). Избегается несильным патчем до ссылки на $a, терпимо и репортить я не стал.
Дедлок в стиле пхп
$a->ref = $b;
$b->ref = $a;
Мне в свое время было интересно, как пхп справится с перекресными ссылками. Зависнет ли? Упадет ли с ошибкой «нельзя покинуть область видимости», и как она будет звучать на английском. Увы, теплица показала — все переменные будут существовать до конца, пока не придет как говорится «or in any order during the shutdown sequence»
Заключение
На данный момент все что я вспомнил. А может и все что я встречал. Но создалось впечатление что деструкторы в ПХП это костыль, так что скорее всего скоро опять наткнусь.
Мне кажется будущее ООП веб-программирование за интерпретатором c++, и возможно он будет готов. Возможно кто то однажды возьмется изменить с++, добавить стандартных конструкций что бы он стал ориентированным под веб. Но пока я альтернатив не нашел.
Php destruct fatal error
Description: ------------ When performing an operation which throws an exception in the __destruct method of a class, the following Error is generated Fatal error: Exception thrown without a stack frame in Unknown on line 0 I have only observed this happening when an object goes out of scope because the script has ended. Rather than generating a scripting engine error, PHP should allow for the script to deal with the error, for instance when an exception handler has been specified by the script. Reproduce code: --------------- class test < function __construct() < echo "Construct\n"; >function greet() < echo "Hello World\n"; >function __destruct() < echo "Destruct\n"; throw new Exception( 'test' ); >> $test = new test(); $test->greet(); Expected result: ---------------- Construct Hello World Destruct Fatal error: Uncaught exception 'Exception' with message 'test' in /home/crazzeto/test.php:13 Stack trace: #0 /home/crazzeto/test.php(13): test::__destruct() #1 /home/crazzeto/test.php(20): test::__destruct() #2 /home/crazzeto/test.php(20): unknown() #3 thrown in /home/crazzeto/test.php on line 13 Actual result: -------------- [crazzeto@DEVEL crazzeto]$ php test.php Construct Hello World Destruct Fatal error: Exception thrown without a stack frame in Unknown on line 0
Patches
Pull Requests
History
Throwing exceptions in __desctruct() is not allowed. Should be documented..
This bug has been fixed in the documentation's XML sources. Since the online and downloadable versions of the documentation need some time to get updated, we would like to ask you to be a bit patient. Thank you for the report, and for helping us make our documentation better. "Attempting to throw an exception from a desctructor causes a fatal error."