Правильное использование буфера вывода

2 февр. 2012 г., 19:37:19
Просмотры: 21.1K
Голосов: 6

Я пытаюсь использовать действия для переопределения вызовов функций, которые у меня есть в шаблоне (чтобы упростить обновление определенных повторяющихся секций). Например, в archives.php у меня следующее:

<?php get_header(); ?>

    <?php roots_content_before(); ?>
    <?php $page_for_posts = get_option( 'page_for_posts' ); if ($page_for_posts) { echo '<h1>' . get_the_title($page_for_posts) . '</h1>'; } ?>
    <h3>
        <?php
            $term = get_term_by('slug', get_query_var('term'), get_query_var('taxonomy'));
            if ($term) {
                echo $term->name;
            } elseif (is_day()) {
                printf(__('Ежедневные архивы: %s', 'roots'), get_the_date());
            } elseif (is_month()) {
                printf(__('Ежемесячные архивы: %s', 'roots'), get_the_date('F Y'));
            } elseif (is_year()) {
                printf(__('Годовые архивы: %s', 'roots'), get_the_date('Y'));
            } elseif (is_author()) {
                global $post;
                $author_id = $post->post_author;
                printf(__('Архивы автора: %s', 'roots'), get_the_author_meta('user_nicename', $author_id));
            } else {
                single_cat_title();
            }
        ?>
    </h3>
    <?php echo category_description(); ?>
    <?php roots_loop_before(); ?>
    <?php get_template_part('loop', 'category'); ?>
    <?php roots_loop_after(); ?>
    <?php roots_content_after(); ?>

<?php get_footer(); ?>

Вы можете видеть некоторые функции, например roots_content_before(); В отдельном файле у меня следующее:

function roots_content_before() { do_action('roots_content_before'); }

и использую это следующим образом:

<?php

    add_action('roots_content_before', 'roots_bootstrap_content_before');

    function roots_bootstrap_content_before() { ?>

        это некоторый текст

    <?php }

?>

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

<?php

    add_action('roots_content_before', 'roots_bootstrap_content_before');

    function roots_bootstrap_content_before() { ob_start(); ?> 

        это некоторый текст

       <?php return ob_get_clean();

    }

?>

Я думаю об этом совершенно неправильно? Я все еще учусь, но пытаюсь некоторое время без какого-либо успеха. Любые указания в правильном направлении были бы действительно оценены. Спасибо!

0
Все ответы на вопрос 2
9
13

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

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

// плагин
ob_start();

// позже, вы в своей теме
ob_start();

// вы вызываете функцию, в которую автор плагина добавил хук:
print ob_get_clean();

// вы вызываете *свою*:
return ob_get_clean();

// результат пустой!

Такие ситуации очень сложно отлаживать. Избегайте их.


Вам не нужна отдельная функция для простого вызова do_action(). Просто напишите do_action('roots_content_before'); в своей теме.

2 февр. 2012 г. 19:55:08
Комментарии

Согласен с toscho здесь. Не используйте буферизацию вывода. Используйте действия и фильтры там, где это необходимо.

Scott Scott
2 февр. 2012 г. 20:11:37

Привет, @toscho, я действительно ценю твой совет. Я только начал читать о буферизации вывода, но из той статьи сложилось впечатление, что это даёт прирост производительности. Есть он на самом деле или нет, но звучит так, будто если ты полностью контролируешь приложение, то это может быть полезно, но поскольку WordPress имеет тысячи плагинов, ты просто можешь напроситься на неприятности ;) Ещё раз спасибо!

Zach Zach
2 февр. 2012 г. 21:19:52

@Zach Эта статья ошибочна с первой же строки. :) Отправляйте вывод пользователю как можно раньше. В темах с долгим выполнением кода я даже вызываю flush() до и после медленного кода, чтобы ускорить отрисовку.

fuxia fuxia
2 февр. 2012 г. 22:05:30

Вот сволочи! ;)

Спасибо за дополнительное разъяснение, @toscho

Zach Zach
3 февр. 2012 г. 22:29:59

Прогрессивный рендеринг через множественные сбросы - стоит прочитать.

fuxia fuxia
3 февр. 2012 г. 22:32:39

toscho, можно использовать вложенные буферы вывода. Хотя терять над ними контроль — не лучшая идея :)

offroff offroff
11 апр. 2012 г. 09:58:07

@offroff В WordPress кто-то другой может добавить нежелательную вложенность. Поэтому не используйте это в плагинах или темах.

fuxia fuxia
11 апр. 2012 г. 13:37:43

Этот ответ немного вводит в заблуждение. Он игнорирует ситуации, в которых можно без проблем использовать буферизацию вывода. Например, у вас есть функция, которая выводит некоторый HTML, и вы хотите вернуть этот HTML. Пока вы не запускаете общие действия или не вызываете функции WP, такие как get_header(), вы должны использовать буферизацию вывода для создания более читаемого кода.

onetrickpony onetrickpony
16 мая 2012 г. 22:26:48

@OneTrickPony В зависимости от точных операций, которые вы выполняете, можно раньше достичь лимита памяти при использовании буферизации вывода, потому что... ну... всё хранится в памяти до вызова ob_end_clean(). Если вам действительно это нужно — используйте. Это то, что я сказал в своем ответе. :)

fuxia fuxia
16 мая 2012 г. 22:52:11
Показать остальные 4 комментариев
3

Ответ @toscho совершенно неверен.

12 мар. 2015 г. 18:20:23
Комментарии

Это звучит немного резко. Я думаю, что @toscho хотел сказать не то, что вложенность невозможна, а то, что если по какой-то причине вы вызовете ob_get_clean() до того, как код, например, другого плагина, который запустил первый ob_start(), вызовет ob_get_clean(), то вы получите неожиданные результаты. Он просто предупреждает, что стоит использовать этот метод только в случае, если нет другого выхода, так как есть подводные камни, которые можно не заметить с первого взгляда.

kraftner kraftner
12 мар. 2015 г. 18:43:49

Вы посмотрели вторую ссылку? Там есть отличное решение, которое как раз решает проблему этого вопроса. Нет ничего неожиданного во вложенности; попробуйте сами: ob_start(); echo "0"; ob_start(); echo "a"; echo ob_get_clean(); echo "1"; $a = ob_get_clean(); echo $a;

Robert Robert
12 мар. 2015 г. 19:03:15

Честно говоря - нет, не посмотрел. Ещё раз повторю, что есть множество способов всё испортить, поэтому лучше использовать этот метод только когда нет другого выхода. На заметку: именно поэтому ответы только со ссылками не приветствуются здесь. Если бы вы добавили суть ваших ссылок в ответ, это сильно помогло бы.

kraftner kraftner
13 мар. 2015 г. 11:45:07