Variable Assignments
bTemplate does not scan and extract all tags that have the correct syntax. This is an important distinction from other template systems. bTemplate looks at all the variables and arrays you have set and searches for matching tags. What this means is that if you set variables, arrays, or even elements in associative arrays that you never reference in your template, you are wasting valuable CPU cyles. This is because for every value you have set, bTemplate calls the PHP str_replace()
function.
Let me give a quick example about how this can be detrimental to performance. Say you have a database with columns id, user_name, and email_address. If you are simply printing a list of user names and email addresses, you should only set those two variables (not the id variable). This is because regardless of whether you have a <tag:id />
in your template, it will still SEARCH for that tag. If it doesn't find it, nothing bad will happen, it will just result in wasted CPU cycles (which comes into play if you have a server with a high CPU load).
So, when you are populating the array that will contain all those values, it is important to only set the values you will be referencing in the template. For example:
$result = mysql_query('SELECT * FROM users');
while($row = mysql_fetch_array($result)) {
$array[] = $row;
}
That doesn't seem too bad, right? But really, $row
contains SIX (that's right, 6) elements (by default).
key | value |
0 | id |
id | id |
1 | user_name |
user_name | user_name |
2 | email_address |
email_address | email_address |
With six elements in the array, this causes bTemplate to call str_replace()
six times per iteration (as opposed to two if all you really need is user_name and email_address). That can really add up if you have complex templates and large arrays.
So what you should do is something like the following:
$result = mysql_query('SELECT user_name, email_address FROM users');
while($row = mysql_fetch_array($result)) {
$array[] = array(
'user_name' => $row['user_name'],
'email_address' => $row['email_address']);
}
Or even better, try this:
$result = mysql_query('SELECT user_name, email_address FROM users');
while($row = mysql_fetch_assoc($result)) {
$array[] = $row;
}
The mysql_fetch_assoc()
function only returns the associative array keys (not numerically indexed). Optionally, you can use the mysql_fetch_array() function with a second argument to accomplish the same thing:
$row = mysql_fetch_array($result, MYSQL_ASSOC);
So now that you understand how the system works, we should go into why it works that way. The assumption I made during the programming of bTemplate is that the programmer using the class would be a competent PHP programmer. This was done in the interest of speed - any critical errors will already be handled by PHP (can't open a file, for instance). I don't believe in the need for layer upon layer of error-checking.
bTemplate leaves in tact any tags you have placed in the template that you haven't assigned a variable to. This means that if a user loads up your page and views the source, he/she will be able to see the bTemplate tags that were not parsed correctly. The assumption is that you'll set a variable for each tag and loop you have in your template.
Looping & Multiple Templates
Currently, if you set an array and then fetch()
a template, the arrays will be erased. This is a design decision that may result in a rework of the looping code, because I'm not sure that this is the desired behavior in most instances. The problem occured when I used a master template (see advanced) and a series of sub-templates. If I assigned a large array destined for a sub-template, the class would indeed parse it correctly, but it would also look for that loop for each and every template used for the entire page. The options at that point were to either use separate objects, thus setting arrays for one template wouldn't bog down the other template at all, or reset the array list after a template was fetched. I chose the latter simply because I don't like messing with multiple template objects in one script.
I am in no way absolutely set in this decision. There may be a time where an array should in fact be used in both the sub-template and the master template (if there were loop markup in both with the same name). Currently, you'd have to assign the array twice - once before the sub-template, and once before the master template. If you have any suggestions or comments, feel free to leave them on the forum.
Wish List
The following features have been requested. My reasoning for or against each request is followed. By virtue of being listed here, the following are currently being considered. Unless otherwise noted, if implemented, these features would be in separate packages (so as not to bloat the base class).
- Control Structures - This would include tags such as
<if:var>
,<else:var>
, and</if:var>
. I think these tags could be very useful, but I'm hesitant to add conditional logic in a template engine. The code itself wouldn't be too difficult. - Caching - Caching is something many web applications can really benefit from. If I add caching, I want to do it right. This means the ability to cache certain templates separately from each other, with the ability to set the time out on a per-template basis. It's not really a difficult thing, but the planning could be a bit time consuming.
- Plugins - This refers to the ability of other programmers having a simple interface to add new syntax and functionality to the class (for example, a
code
plugin that would allow you to highlight certain portions of text like<code:php>$var = 'value';</code:php>
). I believe this is a good idea, but I have yet to come up with a decently fast and intuitive way to accomplish this.