output buffering vs. building page with a class

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

Post Reply
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

output buffering vs. building page with a class

Post by Luke »

I was looking through some old threads and came upon arborint's solution to output buffering, which is basically to just build the page with headers and content and then output it. Like this:

Code: Select all

class Response {
    var $_headers = array();
    var $_content = '';

    function setRedirect($location) {
        $this->addHeader("Location: $location");
    }

    function addHeader($string, $replace=true) {
        $this->_headers[$string] = $replace;
    }

    function addContent($content) {
        $this->_content .= $content;
    }

    function out() {
        if ($this->_headers) {
            foreach ($this->_headers as $string => $replace) {
                header($string, $replace);
            }
        } else {
            echo $this->_content;
        }
    }

}


$response = new Response();

$response->addContent('Hello World!');
$response->setRedirect('other_page.php');

$response->out();
Somebody challenged this solution, saying it is basically the same as the output buffering functions. My question is... what is the difference between doing what arborint does and standard ob_start() ob_flush() etc.?

(Sorry to put you in the hotseat arborint, but I am very interested)
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

A class would be more active while using output buffering is completely passive.
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Post by Luke »

feyd wrote:A class would be more active while using output buffering is completely passive.
I'm not sure I understand exactly what you mean. Passive?
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

Once output buffering is on, you don't do anything special to drop data into its buffer, i.e. passive. With a class you have to explicitly interact with it to add data, i.e. active.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: output buffering vs. building page with a class

Post by Christopher »

My previous post was not very good. Is should at least be:

Code: Select all

class Response {
    var $_headers = array();
    var $_redirect = '';
    var $_content = '';

    function setRedirect($location) {
        $this->_redirect = "Location: $location";
    }

    function addHeader($string, $replace=true) {
        $this->_headers[$string] = $replace;
    }

    function addContent($content) {
        $this->_content .= $content;
    }

    function out() {
        if ($this->_redirect) {
            header($this->_redirect);
            exit;
        } else {
            foreach ($this->_headers as $string => $replace) {
                header($string, $replace);
            }
            echo $this->_content;
        }
    }

}


$response = new Response();

$response->addContent('Hello World!');
$response->setRedirect('other_page.php');

$response->out();
The Ninja Space Goat wrote:Somebody challenged this solution, saying it is basically the same as the output buffering functions. My question is... what is the difference between doing what arborint does and standard ob_start() ob_flush() etc.?
For me, this basic class above does not do anything functionally any better than output buffering. It is more testable though. I don't know which would be better as far as memory and speed.

For HTML page building the obvious improvements would be to add methods like these:

Code: Select all

function addMetaTag() {}
    function addScript() {}
    function addStyle() {}
    function addStylesheet() {}
    function addHead() {}
    function addBodyParam() {}
The alternative to this is to make the response class look a little like a Template class with set() and render() methods, but with a setRenderer() method to all a template object to provide the content instead. Then you can pretty create hierarchical render trees (composite/component pattern) that can mix and match different template types for different parts of the page. This is what I am currently doing.
The Ninja Space Goat wrote:(Sorry to put you in the hotseat arborint, but I am very interested)
Please go wild. I have found that when my code gets ripped to shreds -- I learn the most! ;)
(#10850)
User avatar
Maugrim_The_Reaper
DevNet Master
Posts: 2704
Joined: Tue Nov 02, 2004 5:43 am
Location: Ireland

Post by Maugrim_The_Reaper »

I use a similar Response class - the main difference is as feyd put it the passive vs active. Another way - a Response class can be passed around the application, allow plugin loading to manipulate content, provides a centralised location for other output management (gzip comes to mind as the obvious one), can allow page caching, and well - it has lots of uses if you dig around more. I just find it easier to have a Response object than messing with output buffering and trying to manipulate content from that direction (I find it becomes messy).
Post Reply