PHP: How to implement a __get-like method for local function variables
Question
I'm no stranger to __get(), and have used it to make some very convenient libraries in the past. However, I'm faced with a new challenge (PHP 5.3, abbreviated and simplified my code for this question):
<?php
namespace test;
class View {
function __construct($filename, $varArray) {
$this->filename = $filename;
$this->varArray = $varArray;
}
function display() {
include($this->filename);
}
function __get($varName) {
if (isset($this->varArray[$varName]))
return $this->varArray[$varName];
return "?? $varname ??";
}
}
?>
Above is a very, very simplified system for loading a View. This code would call the view and display it:
<?php
require_once("View.php");
use test\View;
$view = new View("views/myview.php", array("user" => "Tom"));
$view->display();
?>
My goal for this code is to allow the view "myview.php" to contain code like this:
<p>
Hello <?php echo $user; ?>! Your E-mail is <?php echo $email; ?>
</p>
And, used with the above code, this would output "Hello Tom! Your E-mail is ?? email ??"
However, this won't work. The view is being included within a class method, so when it refers to $user and $email, it's looking for local function variables -- not variables belonging to the View class. For this reason, __get never gets triggered.
I could change all my view's variables to things like $this->user and $this->email, but that would be a messy and unintuitive solution. I'd love to find a way where I can reference variables directly WITHOUT having PHP throw an error when an undefined variable is used.
Thoughts? Is there a clean way to do this, or am I forced to resort to hacky solutions?
Solution
EDITING MY ANSWER. Abit of a "hack around" but a potential solution. May want to "reset" the error_handler to more generic functionality.
view.php
<?php
error_reporting(E_ALL);
ini_set("display_errors", 0);
class View {
function display($file, $values) {
set_error_handler(array($this, '__get'), E_NOTICE);
extract($values);
include($file);
}
function __get($vaule)
{
echo '<i>Unknown</i>';
}
}
$View = new View;
$values = array('user' => 'Tom',
'email' => 'email@host.com');
$View->display('/filename.php', $values);
?>
filename.php
Hello <?php echo $user; ?>, your email is <?php echo $email; ?> and your are <?php echo $age; ?> years old.
Output
Hello Tom, your email is email@host.com and your are
Unknown years old.
OTHER TIPS
You can use extract to pull all variables into the local scope:
function display() {
extract($this->varArray);
include($this->filename);
}