Is this a proper way of "loading" views in PHP?
I agree that its a better pattern to wrap your view logic in a class.

Here is some code I whipped together tonight - It represents the simplest class I could devise that contains the minimum logic that I require in a view:


Includes - Ability to include other views
Captures - Ability to easily capture content within your view
Layouts - Ability to inject data into a re-usable layout template
Fetching - Ability to fetch view output instead of sending it to output buffer
data - Ability to access the resulting data once the view is finished


[edit] Refactored per conversation in comments regarding passing $data by reference.

View.php

&lt;?php
/**
 * Simple view class that supports includes, capturing, and layouts, as well
 * as retrieving rendered view content and resulting data.
 *
 * *NOTE* When a view uses a layout, the output of the view is ignored, as
 *        as the view is expected to use capture() to send data to the layout.
 *
 * @author David Farrell &lt;DavidPFarrell@gmail.com&gt;
 */
class View implements ArrayAccess
{
    /**
     * View file to include
     * @var string
     */
    private $file;

    /**
     * View data
     * @var array
     */
    private $data;

    /**
     * Layout to include (optional)
     * @var string
     */
    private $layout;

    /**
     * Constructor
     *
     * @param string $file file to include
     */
    public function __construct($file)
    {
        $this-&gt;file = $file;
    }

    /**
     * render Renders the view using the given data
     *
     * @param array $data
     * @return void
     */
    public function render($data)
    {
        $this-&gt;data = $data;
        $this-&gt;layout = null;

        ob_start();

        include ($this-&gt;file);

        // If we did not set a layout
        if (null === $this-&gt;layout)
        {
            // flush view output
            ob_end_flush();
        }
        // We set a layout
        else
        {
            // Ignore view output
            ob_end_clean();

            // Include the layout
            $this-&gt;include_file($this-&gt;layout);
        }
    }

    /**
     * fetch Fetches the view result intead of sending it to the output buffer
     *
     * @param array $data
     * @return string The rendered view content
     */
    public function fetch($data)
    {
        ob_start();
        $this-&gt;render($data);
        return ob_get_clean();
    }

    /**
     * get_data Returns the view data
     *
     * @return array
     */
    public function get_data()
    {
        return $this-&gt;data;
    }

    /**
     * include_file Used by view to include sub-views
     *
     * @param string $file
     * @return void
     */
    protected function include_file($file)
    {
        $v = new View($file);
        $v-&gt;render($this-&gt;data);
        $this-&gt;data = $v-&gt;get_data();
    }

    /**
     * set_layout Used by view to indicate the use of a layout.
     *
     * If a layout is selected, the normal output of the view wil be
     * discarded.  The only way to send data to the layout is via
     * capture()
     *
     * @param string $file
     * @return void
     */
    protected function set_layout($file)
    {
        $this-&gt;layout = $file;
    }

    /**
     * capture Used by view to capture output.
     *
     * When a view is using a layout (via set_layout()), the only way to pass
     * data to the layout is via capture(), but the view can use capture()
     * to capture text any time, for any reason, even if the view is not using
     * a layout
     *
     * @return void
     */
    protected function capture()
    {
        ob_start();
    }

    /**
     * end_capture Used by view to signal end of a capture().
     *
     * The content of the capture is stored under $name
     *
     * @param string $name
     * @return void
     */
    protected function end_capture($name)
    {
        $this-&gt;data[$name] = ob_get_clean();
    }

    /* ArrayAccess methods */
    public function offsetExists($offset)      { return isset($this-&gt;data[$offset]); }
    public function offsetGet($offset)         { return $this-&gt;data[$offset]; }
    public function offsetSet($offset, $value) { $this-&gt;data[$offset] = $value; }
    public function offsetUnset($offset)       { unset($this-&gt;data[$offset]); }

}


run.php

&lt;?php
require "View.php";

$v = new View('view_main_simple.php');
$fetch = $v-&gt;fetch(array('message' =&gt; 'Hello, world'));
print("Fetch result: {$fetch}\n");

$v = new View('view_main_complex.php');
$v-&gt;render(array('one' =&gt; 1, 'two' =&gt; 2, 'rows' =&gt; array('a','b','c')));

$data = $v-&gt;get_data();

print("\n");
var_export($data);


view_main_simple.php

The message is: &lt;?php echo $this['message'] ?&gt;&lt;br/&gt;


view_main_complex.php

&lt;?php $this-&gt;set_layout('view_layout.php') ?&gt;
&lt;?php $this-&gt;capture() ?&gt;
    one=&lt;?php echo $this['one'] ?&gt;&lt;br/&gt;
    &lt;?php $this-&gt;include_file('view_include.php') ?&gt;
    three=&lt;?php echo $this['three'] ?&gt;&lt;br/&gt;
&lt;?php $this-&gt;end_capture('body') ?&gt;


view_include.php

two=&lt;?php echo $this['two'] ?&gt;&lt;br/&gt;
&lt;?php $this['three'] = 3 ?&gt;
&lt;ul&gt;
    &lt;?php foreach($this['rows'] as $row) { ?&gt;
        &lt;li&gt;&lt;?php echo $row ?&gt;&lt;/li&gt;
    &lt;?php } ?&gt;
&lt;/ul&gt;


view_layout.php

&lt;html&gt;
&lt;body&gt;
&lt;pre&gt;
&lt;?php echo $this['body'] ?&gt;
&lt;/pre&gt;
&lt;/body&gt;
&lt;/html&gt;


Program Output

Fetch result: The message is: Hello, world&lt;br/&gt;

&lt;html&gt;
&lt;body&gt;
&lt;pre&gt;
    one=1&lt;br/&gt;
    two=2&lt;br/&gt;
&lt;ul&gt;
            &lt;li&gt;a&lt;/li&gt;
            &lt;li&gt;b&lt;/li&gt;
            &lt;li&gt;c&lt;/li&gt;
    &lt;/ul&gt;
    three=3&lt;br/&gt;
&lt;/pre&gt;
&lt;/body&gt;
&lt;/html&gt;

array (
  'one' =&gt; 1,
  'two' =&gt; 2,
  'rows' =&gt; 
  array (
    0 =&gt; 'a',
    1 =&gt; 'b',
    2 =&gt; 'c',
  ),
  'three' =&gt; 3,
  'body' =&gt; '   one=1&lt;br/&gt;
    two=2&lt;br/&gt;
&lt;ul&gt;
            &lt;li&gt;a&lt;/li&gt;
            &lt;li&gt;b&lt;/li&gt;
            &lt;li&gt;c&lt;/li&gt;
    &lt;/ul&gt;
    three=3&lt;br/&gt;
',
)