Re: Rate my (really) simple template class

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Feb 14, 2011 at 09:52:51PM -0500, Brian Waters wrote:

> So I decided to write a template class in order to get myself going on
> learning PHP. Of course I wrote the simplest thing possible:
> 
> class Template
> {
>         protected $template;
>         protected $vars;
> 
>         public function __construct($template)
>         {
>                 $this->template = $template;
>         }
> 
>         public function __set($name, $value)
>         {
>                 $this->vars[$name] = $value;
>         }
> 
>         public function __get($name)
>         {
>                 return $this->vars[$name];
>         }
> 
>         public function __toString()
>         {
>                 ob_start();
>                 eval('?>' . $this->template);
>                 return ob_get_clean();
>         }
> }

This is *not* a simple class. You're using magic methods, etc.

> 
> Which you can use, quite simply like this:
> 
> $tpl = new Template(file_get_contents('index.tpl.php'));
> 
> $tpl->title = 'Here\'s the title';
> $tpl->text = 'Blah blah blah...';
> 
> echo $tpl;
> 
> I have a few questions though.
> 
> - First, I'm storing the template as an actual string, instead of just
> a path to a template file, which means I'm using eval() instead of
> require() in my __toString(). My thinking was that this would avoid
> reading the template file twice in the case that __toString() gets
> called multiple times. But will PHP handle this automagically if I do
> in fact decide to store a path to a file, and call require() instead?

Advice: don't use eval() this way. It's slow and dangerous. I'd suggest
simply reading your template file into a class variable in the
constructor. Considering this is a "template" class, you're likely to
need to read the whole thing in at some point anyway. Do it at the
beginning and avoid eval() and the like. Also, you're not obligating
your user to read in the file and pass it to you on the stack, which is
really an abuse of the stack if you can avoid it. And once read in, you
can "vet" it with various PHP functions to ensure it doesn't have
dangerous content when it is eventually output.

> 
> - Secondly, I noticed that in the constructor, it's not necessary to
> initialize $vars to an empty array, and I haven't done so. I guess PHP
> automatically initializes it the first time I set one of its elements
> to a value. Is this okay, or is there a better way in the name of best
> practices?

PHP is a language which doesn't require variables to be initialized
before use. That said, it's probably superior programming practice to do
so anyway. That way, you *know* what's in there when you accidentally
use the variable later (which you will).

> 
> - Finally, I'd like to be able to limit what things can be accessed
> from the scope of the template file. As it stands, if you have a
> function named blowUpTheComputer() or a gobal variable called
> $dontTouchThis, a template author can easily cause trouble. They can
> also access any methods and properties of the Template class. How
> would you go about restricting this?

Now you see the liability of eval(). If you're going to allow
user-defined and evaluated functions in your template, you're going to
have to live with the consequences. Fortunately, the worst thing that's
liable to happen is they hose the website, not the whole computer; PHP
runs with the permissions of the server, which are generally limited to
hacking up files in the web root directories.

Rather than evaluating user functions at runtime, I would instead allow
"hooks", where the user can perhaps "register" a function and you
include() or require() its file later. Drupal uses a scheme vaguely like
this. Of course, you're still stuck if the user is an idiot or
malicious.

Actually, I'd consider a template class like this overkill anyway,
unless you plan to build a templating language and interpreter. Instead,
simply set a variable to the template filename, and just include() it at
some point. Make the user initialize all the variables and read in all
the include files before you do this. They can then do anything they
like within the template, which is generally just a HTML file with some
PHP code in it.

And if you're truly new to PHP, I'd suggest just coding some forms with
PHP to handle the interaction in them as a first action. This will get
you used to the way PHP handles variables, POST and GET, and the like.
Simple stuff without classes, until you're fully comfortable with basic
PHP variable handling, built-in functions, etc.

Paul

-- 
Paul M. Foster
http://noferblatz.com


-- 
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php



[Index of Archives]     [PHP Home]     [Apache Users]     [PHP on Windows]     [Kernel Newbies]     [PHP Install]     [PHP Classes]     [Pear]     [Postgresql]     [Postgresql PHP]     [PHP on Windows]     [PHP Database Programming]     [PHP SOAP]

  Powered by Linux