tags:

views:

94

answers:

2

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?

A: 

You can use extract to pull all variables into the local scope:

function display() {
    extract($this->varArray);
    include($this->filename);
}
elias
That's a good method for making the set variables available, but my other requirement is that I be able to intercept requests for unset variables as well. Unfortunately, this doesn't cover that half of the equation :)
Tom Frost
Sorry, missed that. You can't intercept variables in PHP, so you need to use $this or wrap the variable notation in a function call that checks if the var exists or not.
elias
+1  A: 

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 protected]');

$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 protected] and your are Unknown years old.

bigstylee
Yep, a good solution like elias's, but unfortunately doesn't allow me to intercept undefined variables and display something different for them.
Tom Frost
Please see editted post :)
bigstylee
Hacky, but quite functional :) I'd want to throw it to a function other than __get to parse out the variable name, but this works nicely! I'll just have to see how it plays with my existing error handler :) Thanks, bigstylee!
Tom Frost
I wouldn't rely on the fact that notice errors are produced only for unknown variables...
StasM