Я прочитал немало материалов в Интернете, где разные авторы предлагают использовать буферизацию вывода. Самое забавное, что большинство авторов аргументируют его использование только потому, что он позволяет смешивать заголовки ответов с фактическим содержимым. Честно говоря, я думаю, что ответственные веб-приложения не должны смешивать вывод заголовков и контента, а веб-разработчикам следует искать возможные логические недостатки в своих сценариях, которые приводят к отправке заголовков после вывода. Это мой первый аргумент против API-интерфейса буферизации вывода ob_*
. Даже для этого небольшого удобства вы получаете – микширование заголовков с выходом – это не очень хорошая причина для его использования, если не нужно быстро взламывать скрипты, что обычно не является целью и способом серьезного веб-приложения.
Кроме того, я думаю, что большинство людей, работающих с API буферизации вывода, не думают о том, что даже без явной буферизации вывода, PHP в сочетании с веб-сервером, в который он подключен, все равно выполняет некоторую внутреннюю буферизацию . Легко проверить – сделать эхо короткой строки, спать на 10 секунд и сделать еще одно эхо. Запросите свой скрипт в браузере и посмотрите паузу на странице в течение 10 секунд, после чего обе строки появятся. Прежде чем некоторые говорят, что это артефакт рендеринга, а не трафик, отслеживающий фактический трафик между клиентом и сервером, показывает, что сервер сгенерировал заголовок Content-Length
с соответствующим значением для всего вывода, что означает, что вывод не был отправлен постепенно с каждым echo
вызовом, но накапливается в некотором буфере и затем отправляется при завершении сценария. Это одна из моих проблем с явной буферизацией вывода – почему нам нужны две разные реализации буфера вывода друг над другом? Может быть, это связано с тем, что внутренняя (недоступная) буферизация вывода на PHP / Web-сервере зависит от условий, которые разработчик PHP не может контролировать и, следовательно, не может использоваться?
В любом случае, я задумался, что нужно избегать явной буферизации вывода (серии функций ob_*
) и полагаться на неявный, помогая ему с хорошей функцией flush
, когда это необходимо. Возможно, если бы на веб-сервере была какая-то гарантия для отправки вывода клиенту с каждым вызовом echo / print, тогда было бы полезно настроить явную буферизацию – ведь никто не хочет отправлять ответ клиенту с 100 байтовые куски. Но альтернатива с двумя буферами кажется несколько бесполезным слоем абстракции.
Итак, в конечном счете, для серьезных веб-приложений нужна буферизация вывода?
Серьезным веб-приложениям требуется буферизация вывода в одной конкретной ситуации:
Ваше приложение хочет контролировать то, что выводится каким-то сторонним кодом , но нет API для контроля того, что этот код испускает.
В этом случае вы можете вызвать
ob_start()
непосредственно перед передачей управления этому коду, запутаться с тем, что написано (в идеале, с обратным вызовом или путем изучения содержимого буфера, если необходимо), а затем вызовомob_flush()
.
В конечном счете, функции ob_ PHP являются механизмом для захвата того, что делает какой-то другой бит кода в буфер, с которым вы можете столкнуться .
Если вам не нужно проверять или изменять то, что записано в буфер, ничего не получается при использовании ob_start()
.
Вполне вероятно, что ваше «серьезное применение» на самом деле является какой-то структурой.
Вам не нужно ob_start()
, чтобы использовать буферизацию вывода. Ваш веб-сервер уже блокирует ваш вывод.
Использование ob_start()
не улучшает буферизацию вывода – на самом деле это может увеличить использование памяти и задержку использования вашего приложения за счет «накопления» данных, которые веб-сервер в противном случае отправил бы клиенту.
ob_start()
… В некоторых случаях вам может потребоваться контроль, когда веб-сервер очищает свой буфер, основываясь на некоторых критериях, которые лучше всего подходят вашему приложению. В большинстве случаев вы знаете, что вы только что закончили писать логический «блок», который клиент может использовать, и вы говорите, что веб-сервер теперь скрывается и не дожидаться, когда буфер вывода будет заполнен. Чтобы сделать это, просто необходимо исправить ваш выход как обычный, и акцентировать его на flush()
.
Реже, вы захотите удержать данные с веб-сервера, пока у вас не будет достаточно данных для отправки. Не нужно прерывать клиента с половиной новостей, особенно если остальная часть новостей займет некоторое время, чтобы стать доступной. Простое ob_start
позднее завершившееся ob_end_flush()
действительно может быть самой простой и подходящей задачей.
Если ваша заявка берет на себя ответственность за вычисление заголовков, которые могут быть определены только после получения полного ответа, тогда это может быть приемлемым.
Однако даже здесь, если вы не можете сделать ничего лучше, чем получить заголовок, проверив полный выходной буфер, вы можете также позволить веб-серверу (если он будет). Код веб-сервера написан, протестирован и скомпилирован – вы вряд ли улучшаете его.
Например, было бы полезно установить заголовок Content-Length
если ваше приложение знает длину тела ответа после того, как оно вычислит тело ответа.
Вы не должны ob_start()
чтобы избежать дисциплин:
Если вы это сделаете, они вызовут технический долг, который заставит вас плакать один день.
Хорошо, вот настоящая причина: выход не запускается, пока все не будет сделано. Представьте приложение, которое открывает соединение SQL и не закрывает его перед началом вывода. Случается, что ваш скрипт получает соединение, начинает выводить, ждет, когда клиент получит все, что ему нужно, а затем, в конце, закроет соединение. Woot, соединение 2s, где достаточно 0,3 с.
Теперь, если вы буферизируете, ваш скрипт подключается, помещает все в буфер, автоматически отключается в конце, а затем начинает отправлять сгенерированный контент клиенту.
Если вы хотите выводить отчет на экран, но также отправлять его по электронной почте, буферизация вывода позволяет вам не повторять обработку для вывода вашего отчета дважды.
Наиболее очевидными случаями использования являются:
ob_gzhandler
или любое количество фильтров, которые вы могли бы разработать самостоятельно); Я сделал это с API-интерфейсами, которые поддерживают только выходные данные (а не возвращаемые значения), где я хотел бы выполнить последующий синтаксический анализ с помощью библиотеки phpQuery . Я использую буферизацию вывода по одной причине … он позволяет мне отправить заголовок «location» после того, как я начал обрабатывать запрос.
Буферизация вывода имеет решающее значение для IIS, которая не делает внутренней внутренней буферизации. Когда выходная буферизация отключена, скрипты PHP работают намного медленнее, чем на Apache. Включите его, и они работают много раз быстрее.
Это старый вопрос, но никто не сказал, что важная особенность буферизации outbut – фильтрация . Перед отправкой клиенту можно предварительно обработать буфер.
Это очень мощная концепция и открывает множество интригующих возможностей. В проекте я использовал два фильтра одновременно:
Чтобы включить выходную фильтрацию, вызовите ob_start("callback")
где callback
является именем функции фильтрации. Для получения дополнительной информации см. Руководство по PHP для ob_start
: http://php.net/manual/en/function.ob-start.php
Я использую буферизацию вывода, чтобы избежать генерации HTML путем конкатенации строк, когда мне нужно знать результат операции рендеринга, чтобы создать некоторый вывод, прежде чем использовать рендеринг.
Мы использовали его в тот же день для страниц с чрезвычайно длинными таблицами, заполненными данными из базы данных. Вы очищаете буфер каждые x строк, чтобы пользователь знал, что страница действительно работает. Затем кто-то услышал об удобстве использования, и на страницах, подобных этому, были найдены поисковые запросы и поисковые запросы.
Это полезно, если вы пытаетесь отобразить индикатор выполнения во время страницы, на выполнение которой требуется некоторое время. Поскольку PHP-код не является многопоточным, вы не можете это сделать, если обработка зависает, выполняя 1 функцию.
Используйте буферизацию вывода для кэширования данных в файле, для других подобных запросов, если вы выполняете много транзакций и обработки базы данных.