Closed reinink closed 10 years ago
Totally agree on that. Mainly because global functions conflicts happen way to often, e.g. it is impossible to use klein\klein with anything that requires illuminate\support.
@SxDx Thanks for taking the time to read. I wanted to get this stuff written down, because I'm sure it will come up in the future and I'll want to know why I decided against it. ;)
Closures wouldn't suffer from the scope issues that variables suffer from, as all functions are known before the rendering begins. They can also be dynamically generated, and therefore don't suffer from the autoloading issues. Honestly, if variable access was possible this way (which is isn't , see above), I'd seriously consider this.
This is actually a very bad idea, as all function names (core and extensions) could then conflict with template variables, which would be very annoying. For example: $data
, $layout
, $content
, $child
, $start
, $end
, $e
, $escape
, $asset
, $batch
.
Isn't possible to define this functions inside the Template class namespace ?
The idea
I have investigated the possibility of making template functions available without using the
$this
operator. For example, instead of calling$this->layout('template')
you could uselayout('template')
. The purpose of doing this is to try reduce the amount of unnecessary syntax within the templates. Below are my findings.The implementation
There is no way to dynamically create user-defined functions in PHP, which means all template functions, including extension functions, need to explicitly defined. Here is an example of this using the
layout()
function:The template (and extension) functions require an instance of the template object, however, in global scope the template is not available. The workaround here is to add a
public static $instance
parameter to the template object which is temporarily assigned during rendering. This requires the following updates to the template object:Enable/disable this feature
A new engine option could even be made available to enable this feature, such as
$engine->useGlobalFunctions(boolean)
. Setting this option to true would automatically include the template functions. This could be implemented within the template'srender()
method like this:The issues
While the above implementation works, there are a number of problems:
Too many global functions
The most obvious issue is that the new global template functions could conflict with other libraries and application code. For example, is it really that smart to have a global
insert()
function just for the sake of this feature?Issues around autoloading
As far as I can see, functions must be included in a separate
functions.php
file, as opposed to just adding them to the bottom of the existing class files. For some reason when using class autoloading, functions defined at the bottom of a class file are not available at runtime. However, adding them to a separate file and then including them seems to work fine. For the main template functions (ie. layout, start, stop, child, insert, etc.) this isn't a big deal as it could be worked into the library, but it certainly adds a layer of complexity when creating extensions.Consistency with variable access
In my mind this feature would only make sense if the same approach could be taken with variable access as well, essentially making it possible to access both functions and variables without the
$this
operator. However, this is very unlikely, as there is no way to make ALL template variables accessible in local scope, given how Plates has been designed.This is quite easy to do with variables assigned outside of a template (ie. in a controller). These can be converted to the local scope easily within the template's
render()
method like so:However, what makes Plates so powerful is its ability to assigned variables within the templates themselves. For example, you may assign your page title at the top of your template like this:
<?php $this->title = 'About Us' ?>
.Since these variables are assigned to the template object during the rendering process, there is no way to convert them to variables in the local scope. Sure, you could assign them immediately to the local scope (ie.
<?php $title = 'About Us' ?>
), but then they would not be available to other included templates (ie. layout and nested). Not good.The problem worsens for helper functions, like the inheritance
start('sidebar')
andstop()
functions. The content generated between these two functions is saved as a parameter of the template object itself, making them available to all included templates (ie.<?=$this->sidebar?>
). Again, in this situation there is no way to convert this new object parameter into a local scope variable (ie.<?=$sidebar?>
), as the local scope is actually within therender()
method.So, unless template variables can be made entirely available without the
$this
operator, it would only add confusion to have some variables available this way, and others not.Closing thoughts
One "last ditch" idea I had was to make all functions within local scope accessible using closures, which are actually aliases to the underlying object methods. So, for example,
$this->layout('template')
could become$layout('template')
. Closures wouldn't suffer from the scope issues that variables suffer from, as all functions are known before the rendering begins. They can also be dynamically generated, and therefore don't suffer from the autoloading issues. Honestly, if variable access was possible this way (which is isn't , see above), I'd seriously consider this.Finally, a simple option would be to just assign the
$this
operator to a shorter variable name, such as$t
. I'm personally not a fan of this given that 1) it could conflict with local scope variables, 2) it makes it less clear that the template is essentially an object, and 3) it only saves 3 characters.Because of the above issues, this idea will not be added to Plates at this time. Accessing all template variables and functions using the
$this
operator keeps things very "neat and tidy". It also makes it very obvious that it's a template specific variable or function.