Почему выходная буферизация использования в PHP?

Я считал довольно мало материала в Интернете, где различные авторы предлагают использовать выходную буферизацию. Забавная вещь состоит в том, что большая часть аргумента авторов в пользу его использования только потому, что он допускает смешивание заголовков ответа с фактическим содержанием. Откровенно говоря, я думаю, что ответственные веб-приложения не должны смешивать заголовки вывода и содержание, и веб-разработчики должны искать возможные логические дефекты в своих сценариях, которые приводят к заголовкам, отправляемым после того, как вывод был сгенерирован. Это - мой первый аргумент против ob_* вывод, буферизующий API. Даже для того небольшого удобства Вы добираетесь - смешивание заголовков с выводом - это не достаточно хорошая причина использовать его, если не нужно изрубить сценарии быстро, который обычно является не целью, ни путем в серьезном веб-приложении.

Кроме того, я думаю, что большинство людей, имеющих дело с выводом, буферизующим API, не думает о том, что даже без явной выходной буферизации включил, PHP в сочетании с веб-сервером, это включено, все еще делает некоторую внутреннюю буферизацию так или иначе. Легко проверить - делают эхо некоторой короткой строки, сон для говорит 10 секунд и делает другое эхо. Запросите свой сценарий с браузером и наблюдайте пустую паузу страницы в течение 10 секунд с обеими строками, появляющимися после этого. Прежде чем некоторые говорят, что это - артефакт рендеринга, не, трафик, прослеживая фактический трафик между клиентом и сервером показывает, что сервер генерировал Content-Length заголовок с соответствующим значением для всего вывода - предполагающий, что вывод прогрессивно не отправлялся с каждым echo звоните, но накопленный в некотором буфере и затем отправленный после завершения сценария. Это - одно из моих схватываний с явной выходной буферизацией - почему нам нужны две различных реализации буфера вывода друг сверху друга? Это может быть, потому что внутренняя (недоступная) выходная буферизация PHP/Web-server подчиняется условиям, которыми разработчик PHP не может управлять и таким образом не действительно применим?

В любом случае, я для одного, начните думать, что нужно избежать явной выходной буферизации (серия ob_* функции), и полагаются на неявный, помогая ему с пользой flush функция, при необходимости. Возможно, если бы была некоторая гарантия от веб-сервера, чтобы на самом деле отправить вывод клиенту с каждым вызовом эха/печати, то было бы полезно настроить явную буферизацию - после всех, что каждый не хочет отправлять ответ клиенту приблизительно с 100-байтовыми блоками. Но альтернатива с двумя буферами походит на несколько бесполезный слой абстракции.

Так, в конечном счете серьезные веб-приложения должны произвести буферизацию?

27
задан amn 24 January 2011 в 13:06
поделиться

8 ответов

  <label ... style = "width: auto; color: inherit" />
-121--2669365-

Поскольку Character.MAX _ VALUE и Character.MIN _ VALUE не являются числовыми. Character.getNumericValue (char) возвращает -1, если параметр не является символом, сопоставляемым с числом.

Числовые символы (0-9), буквенные символы (A-Z) и другие числовые символы Юникода связаны со значениями. Я не знаю всех остальных символов, которые отображены. Но многие персонажи просто вернут -1.

-121--3260543-

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

3
ответ дан 28 November 2019 в 05:21
поделиться

Выходная буферизация имеет решающее значение на IIS, которая не имеет собственной внутренней буферизации. С выключенными выходными буферизацией, скрипты PHP, кажется, запущены намного медленнее, чем на Apache. Включите его, и они бегут много раз быстрее.

3
ответ дан 28 November 2019 в 05:21
поделиться

Я использую выходную буфертуру, чтобы избежать генерации HTML по строке Concatenation, когда мне нужно знать результат операции рендеринга для создания некоторого вывода до Я использую рендеринг Отказ

2
ответ дан 28 November 2019 в 05:21
поделиться

Это полезно, если вы пытаетесь отобразить панель прогресса во время страницы, которая занимает некоторое время для обработки. Поскольку PHP-код не мультиспонден, вы не можете сделать это, если обработка зависает вверх, выполняя функцию 1.

0
ответ дан 28 November 2019 в 05:21
поделиться

Хорошо, вот настоящая причина: выход не запускается, пока не будет сделано все. Представьте себе приложение, которое открывает SQL соединение и не закрывает его перед запуском вывода. Происходит то, что ваш скрипт получает соединение, начинает выводить данные, ждет, пока клиент получит все, что ему нужно, а затем, в конце, закрывает соединение. Woot, соединение 2s, где достаточно 0.3s.

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

9
ответ дан 28 November 2019 в 05:21
поделиться

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

5
ответ дан 28 November 2019 в 05:21
поделиться

существуют много различий, но самый большой, я могу думать о том программисты, происходящие из Java/C# всегда, понимает превратно, и который они никогда не понимают , они имеют неправильно, семантика значения C++.

В C#, вы привыкли использовать новый любое время, вы хотите создать объект. И каждый раз, когда мы говорим об экземпляре класса, мы действительно имеем в виду "ссылку на экземпляр класса". Foo x = y не копирует объект y, он просто создает другую ссылку на любой объект год ссылки.

В C++, существует ясное различие между локальными объектами, выделенными без новое ( Foo f или Foo f (x, y) , и динамично выделенные ( Foo* f = новый Foo () или Foo* f = новый Foo (x, y) ). И в терминах C#, все - тип значения. Foo x = y на самом деле создает копия из сам объект Foo.

, Если вы хотите ссылочную семантику, можно использовать указатели или ссылки: Foo& x = y создает ссылку на объект y. Foo* x = &y создает указатель на адрес, в котором расположен y. И копирование указателя делает просто что: это создает другой указатель, который указывает на то, на что указал исходный указатель. Таким образом, это подобно ссылочной семантике C#.

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

Динамично выделенные объекты не уничтожаются, до вы вызов удаляет .

До сих пор, вы, вероятно, со мной. Вновь прибывшим к C++ преподают это довольно скоро. Хитрая часть находится в том, что этот средства , как это влияет на ваш стиль программирования:

В C++, значение по умолчанию должно быть должно создать локальные объекты. Не выделяйте с новый , если вы абсолютно не имеете к.

при необходимости в динамично выделенных данных сделайте их ответственностью класса. (Очень) упрощенный пример:

class IntArrayWrapper {
  explicit IntArrayWrapper(int size) : arr(new int[size]) {} // allocate memory in the constructor, and set arr to point to it
  ~IntArrayWrapper() {delete[] arr; } // deallocate memory in the destructor

  int* arr; // hold the pointer to the dynamically allocated array
};

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

Так говорят, что нам был нужен массив x целых чисел, вместо того, чтобы делать это:

void foo(int x){
  int* arr = new int[x];
  ... use the array ...
  delete[] arr; // if the middle of the function throws an exception, delete will never be called, so technically, we should add a try/catch as well, and also call delete there. Messy and error-prone.
}

можно сделать это:

void foo(int x){
  IntArrayWrapper arr(x);
  ... use the array ...
  // no delete necessary
}

, Конечно, это использование локальных переменных вместо указателей или ссылок означает, что объекты копируются вокруг не так мало:

Bar Foo(){
  Bar bar;
  ... do something with bar ...
  return bar;
}

в приведенном выше виде возвращаем копию объекта bar . Мы можем вернуть указатель или ссылку, но поскольку экземпляр, созданный внутри функции, выходит из области действия и уничтожается в момент возвращения функции, мы не смогли указать на это. Мы можем использовать new , чтобы выделить экземпляр, который изживает функцию, и вернуть функцию , который - и затем мы получаем все головные боли в управлении памятью, чтобы выяснить, чья обязанность - удалить объект, и когда это должно произойти. Это не очень хорошая идея.

Вместо этого класс Bar должен быть просто разработан таким образом, чтобы копирование выполняло все необходимое. Возможно, он должен внутренне вызвать new для выделения объекта, который может жить до тех пор, пока он нам нужен. Тогда мы могли бы сделать копирование или назначение «украсть» этот указатель. Или мы могли бы реализовать какую-то схему отсчета ссылок, где копирование объекта просто увеличивает счетчик ссылок и копирует указатель, который затем должен быть удален не при уничтожении отдельного объекта, а когда последний объект уничтожается и счетчик ссылок достигает 0.

Но часто мы можем просто выполнить глубокую копию и клонировать объект целиком. Если объект включает динамически выделяемую память, мы выделяем больше памяти для копии. Это может звучать дорого, но компилятор C++ хорош в устранении ненужных копий (и на самом деле в большинстве случаев позволяет исключить операции копирования, даже если они имеют побочные эффекты).

Если вы хотите избежать копирования еще больше, и готовы мириться с немного более неуклюжим использованием, вы можете включить «move semantics» в ваших классах, а также (или вместо) «copy semantics». Стоит приобщиться к этой привычке, потому что (а) некоторые объекты нелегко скопировать, но их можно переместить (например, класс Socket ), (б) это образец, установленный в стандартной библиотеке, и (в) он получает поддержку языка в следующей версии.

С помощью семантики перемещения можно использовать объекты как своего рода «переносимый» контейнер. Это содержимое, которое движется. В текущем подходе это делается путем вызова swap , который обменивает содержимое двух объектов одного типа. Когда объект выходит из области действия, он уничтожается, но если сначала заменить его содержимое на ссылочный параметр, содержимое побега уничтожаться по окончании области действия. Поэтому необязательно выполнять весь путь и использовать ссылочные считанные смарт-указатели только для того, чтобы обеспечить возврат сложных объектов из функций. Неуклюжесть обусловлена тем, что невозможно возвратить их - их необходимо поменять местами в ссылочном параметре (в некоторой степени аналогичном параметру ref в C #). Но поддержка языка в следующей версии C++ решит эту проблему.

Так что самый большой C # до C++ gotcha я могу думать: не делать указатели по умолчанию.Использовать семантику стоимости и вместо этого скроить ваши классы, чтобы вести себя способ, которым вы хотите, когда они скопированы, созданы и разрушены.

Несколько месяцев назад я попытался написать серию блогов для людей в вашей ситуации:
Часть 1
Часть 2
Часть 3

Я не 100% доволен тем, как они оказались, но вы все еще можете найти их полезными.

И когда вы чувствуете, что никогда не получите контроль над указателями, это сообщение может помочь.

-121--1469287-

Наиболее очевидными примерами использования являются:

  1. выходной фильтр (например, ob _ gzhandler или любое количество фильтров, которые вы можете разработать самостоятельно); Я сделал это с API, которые поддерживают только выходные данные (а не возвращаемые значения), где я хотел бы выполнить последующий анализ с помощью библиотеки, такой как phpQuery .
  2. Обслуживание (а не перезапись) кода, написанного со всеми обсуждаемыми вами проблемами; сюда входят такие вещи, как отправка заголовков после начала вывода (кредит Дон Дикинсон) или подавление определенного вывода, который уже был сгенерирован.
  3. Пошаговый выпуск (кредит здесь Тому и Лэнгдону); обратите внимание, что тесты могли завершиться неудачей, поскольку они конфликтуют с внутренним буфером PHP/Apache по умолчанию, но это возможно , это просто требует, чтобы определенная сумма была удалена, прежде чем PHP отправит что-либо - PHP все равно будет держать соединение открытым.
5
ответ дан 28 November 2019 в 05:21
поделиться

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

1
ответ дан 28 November 2019 в 05:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: