I have quite a lot of PHP view files, which I used to include in my controllers using simple include statements. They all use methods declared in a view class which they get like $view->method(); However I recently decided that it would be better if the including would also be done by this view class. This however changes the scope of the included file so that $view is no longer defined. Here is a code example:
in someViewFile.php (BOTH siuations)
<html>
<head><title><?php echo $view->getAppTitle(); ?></title>
etc.
OLD SITUATION in controller:
$view = new view;
include('someViewFile.php'); //$view is defined in someViewFile.php
NEW SITUATION in controller:
$view = new view;
$view->show('someViewFile'); //$view is not defined in someViewFile.php
Right now I hacked my way around the problem using this in the view class:
public function show($file){
$view = &$this;
include($file.".php");
}
Is there anyway to declare the scope of the inluded file or is this the best way of solving the problem?
These examples are off coarse simplified.
Here' a simplified but functional view class that I've seen around quite a lot and use quite a lot.
As you can see in the code below: you instantiate a view with the filename of the template file.
The client code, probably a controller, can send data into the view. This data can be of any type you need even other views.
Nested views will be automatically rendered when the parent is rendered.
Hope this helps.
// simple view class
class View {
protected $filename;
protected $data;
function __construct( $filename ) {
$this->filename = $filename;
}
function escape( $str ) {
return htmlspecialchars( $str ); //for example
}
function __get( $name ) {
if( isset( $this->data[$name] ) ) {
return $this->data[$name];
}
return false;
}
function __set( $name, $value ) {
$this->data[$name] = $value;
}
function render( $print = false ) {
ob_start();
include( $this->filename );
$rendered = ob_get_clean();
if( $print ) {
echo $rendered;
return;
}
return $rendered;
}
function __toString() {
return $this->render();
}
}
Usage
// usage
$view = new View( 'template.phtml' );
$view->title = 'My Title';
$view->text = 'Some text';
$nav = new View( 'nav.phtml' );
$nav->links = array( 'http://www.google.com' => 'Google', 'http://www.yahoo.com' => 'Yahoo' );
$view->nav = $nav;
echo $view;
The templates
//template.phtml
<html>
<head>
<title><?php echo $this->title ?></title>
</head>
<body>
<?php echo $this->nav ?>
<?php echo $this->escape( $this->text ) ?>
</body>
</html>
//nav.phtml
<?php foreach( $this->links as $url => $link ): ?>
<a href="<?php echo $url ?>"><?php echo $link ?></a>
<?php endforeach ?>
You can't change include() scope, no, so your method is probably about as good as it gets in the situation you're describing. Though I'd skip the ugly PHP4-compat ampersand, myself.
What i do, ( i don't know how OK it is) is simply
extract($GLOBALS);
include $view.".php";
Sure as hell works
Cheers!
An even more simplified version of a View class:
Class View {
protected $filename;
function __construct($filename){
$this->filename = $filename;
}
function display(){
global $session; //put global variables here
include Cfg::ROOT . '/views/' . $this->filename;
}
function assign($key, $val){
$this->$key = $val;
}
}
In controller:
$view = new View('homepage.php');
$view->assign('page_title',$page_title); //assign all needed variables from controller
$view->display();
In the template/view file:
echo $this->page_title;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With