Я работал с потоками ресурсов, а точнее с fopen () .
Эта функция выдает предупреждение при сбое, в дополнение к возвращению false вместо ресурса. Нежелательные предупреждения являются проблемой, я решил их подавить.
Мне пришло в голову две возможности: использовать оператор подавления ошибок @ или set_error_handler (). И, сказав, что у @ были не очень хорошие показатели и часто создавало больше проблем, чем решало, я провел быстрый тест, чтобы увидеть, как set_error_handler () справился с этим.
А вот и проблемный код:
<?php
error_reporting(E_ALL);
function errorHandler(int $errorNumber, string $errorMessage)
{
throw new \Exception();
}
$previousHandler = set_error_handler("errorHandler");
$operations = 10000;
for($i = 0; $i < $operations; $i++) {
try{
$inexistant[0];
} catch (\Exception $e) {}
}
set_error_handler($previousHandler);
echo 'ok';
Выполнение этого простого кода приведет к сбою сервера apache с таким сообщением:
[mpm_winnt:notice] [pid 6000:tid 244] AH00428: Parent: child process 3904 exited with status 3221225725 -- Restarting.
После поиска это сообщение означает, что на сервере произошла ошибка нарушения доступа, главным образом в случае достижения предела размера стека. Это, однако, не должно иметь место, так как этот код не должен увеличивать размер стека (и фактически он не увеличивает фреймы стека PHP).
Я также проверил, важно ли было время, но даже при перерыве в 3 мс между каждой итерацией сбой происходит после более или менее одинакового количества итераций. Это число составляет около 700, но колеблется очень незначительно, иногда работает нормально на 704, а иногда нет.
Кроме того, поиск в трекере ошибок php не показывает ничего релевантного, за исключением, может быть, этой записи об ошибке , которая говорит о том факте, что происходит обработка вызова функции обработки. Это может означать, что существует вероятность того, что исключение может обойти некоторую обработку при выходе из функции, но, поскольку я ничего не знаю об исходном коде PHP, это чисто предположение.
Поскольку я хотел бы правильно распространить сообщение об ошибке, способ с использованием set_error_handler () был бы наиболее разборчивым, но я знаю, что могу использовать error_get_last () и оператор @ для достижения того же самого цель с гораздо большим количеством кода (поскольку в реальном проекте есть несколько функций, таких как fopen (), вызываемых одна за другой).
Итак, вот вопросы: это ошибка PHP? Есть ли способ обойти эту проблему, сохраняя чистый код?
Спасибо.
PS: я знаю, что причина для эталонного теста ... сомнительна в лучшем случае, и я должен взять любой код, который будет наиболее разборчивым, при условии, что производительность жизнеспособна, но это все же заставило меня обнаружить этот интересный момент кода.
Редактировать: я забыл поставить версии, с которыми я тестировал:
- Windows 7, Apache 2.4.38, PHP 7.3.2 через XAMPP
- Windows 7, Apache 2.4.29, PHP 7.2.2 через XAMPP
- Ubuntu Server 18.04, Apache / 2.4.29 (Ubuntu), PHP 7.2.15-0ubuntu0.18.04.1