bTemplate is a class designed to allow the complete separation of program logic (PHP code) and presentation (HTML, XML, etc.). There are quite a few discussions on why this is important floating around the various PHP sites. The quick answer is that, if properly designed, it allows you to work on your programs independently of your web site design. This means you can have designers that know nothing about PHP working on the site design (in whatever editor they want) without fear of them messing up your PHP code. It also means that (if properly designed), you can change the entire look of the site simply by editing a template or two. Since your PHP code isn't embedded into all the HTML pages, there's no need to go mucking through mixed PHP/HTML each time you want a layout change. If you're not sold yet, check out some of the various articles listed below (in no paticular order).

Advantages

The advantages of template systems are listed above. The following are what I feel are advantages of bTemplate over other PHP template classes (you can research other systems simply by clicking the links in the sidebar).

Disadvantages

While I believe bTemplate is a great solution to a common problem, it isn't for everyone. However, there are (as always) some disadvantages to using this class.

If you currently use a template system and are happy with it's speed and features, there's no reason to switch. If this template system doesn't have the features you're looking for, there's no reason to start using it. If you don't like the syntax and don't feel like changing it in the class, don't bother downloading it. In short, this is a class designed for people that need a template class, but don't want to deal with the bloated and slow libraries that are already out there.

Note: My claims that bTemplate is "faster" than other template systems are solely based on my experience with a few of them (FastTemplate, Smarty, PHPLib Templates) as well as an examination of some of their code and features. I am planning a benchmark page in the near future that may or may not substantiate my claims. When this happens, I will in fact post benchmarks that are favorable to bTemplate as well as unfavorable. If you have a template system and want to be included in the benchmarks, check the benchmarks page (when it goes up) for instructions on how to get added.

How it Works

bTemplate is based on the assumption that the programmer shouldn't have to worry about coding a loop to assign variables to a block (or "section" in Smarty-speak). The idea behind bTemplate (and it's not an original one) is that the programmer simply populates an array and sets it once to the template. The template class is responsible for looping through that array, detecting any nested arrays (arbitrarily deep), and interpolating the values into the template automatically.

Let's go into a basic example. This example simply shows scalar tags, loops will be looked at shortly.

simple.tpl:

<html>
  <head>
    <title><tag:title /></title>
  </head>

  <body>
    <p>Hello, <tag:name /></p>
  </body>
</html>

The corrosponding PHP page would look something like this. (There's no need to have a corrosponding PHP page for each template, that's just how the examples are being written.)

simple.php:

<?php
$title = 'My Simple Template Example';
$name = 'L.E. Modesitt, Jr.';

include_once('bTemplate.php');
$tpl = new bTemplate();

$tpl->set('title', $title);
$tpl->set('name', $name);

echo $tpl->fetch('simple.tpl');
?>

Please note that there is no need to name the variable identical to the tag in the template. For example, $tpl->set('name', $honey_maid_grahams); is perfectly acceptable (easy to read is another matter).

The resulting outputted & interpolated template from the above two examples will look like this.

<html>
  <head>
    <title>My Simple Template Example</title>
  </head>

  <body>
    <p>Hello, L.E. Modsitt, Jr.</p>
  </body>
</html>

Loops

Using the loop tag forces bTemplate to iterate over the elements of the assigned array.

loop.php:

<?php
$names = array('Tom', 'Dick, 'Harry');

include_once('bTemplate.php');
$tpl = new bTemplate();

$tpl->set('names', $names);

echo $tpl->fetch('loop.tpl');
?>

loop.tpl:

<ul>
  <loop:names>
    <li><tag:names[] /></li>
  </loop:names>
</ul>

This simply prints out a bulleted list of all the names that were in the array. The [] after the tag name signifies that it's referencing a single element in a loop rather than a scalar $names variable. The resulting output would look like this.

<ul>
    <li>Tom</li>
    <li>Dick</li>
    <li>Harry</li>
</ul>

Associative Arrays

Associative arrays are arrays that have strings as keys instead of integers. You can set an associative array just like you set a regular array or a scalar value.

assoc.php:

<?php
$record = array(
  'name' => 'Tom',
  'phone' => '555-1212',
  'zip' => '77777'
);

include_once('bTemplate.php');
$tpl = new bTemplate();

$tpl->set('record', $record);

echo $tpl->fetch('assoc.tpl');
?>

assoc.tpl:

<html>
  <head>
    <title>Associative Array Example</title>
  </head>

  <body>

  <table>
    <tr>
      <td>Name</td>
      <td>Phone</td>
      <td>Zip</td>
    </tr>
    <tr>
      <td><tag:record.name /></td>
      <td><tag:record.phone /></td>
      <td><tag:record.zip /></td>
    </tr>
  </table>

  </body>
</html>

The result from this example would be like this.

<html>
  <head>
    <title>Associative Array Example</title>
  </head>

  <body>

  <table>
    <tr>
      <td>Name</td>
      <td>Phone</td>
      <td>Zip</td>
    </tr>
    <tr>
      <td>Tom</td>
      <td>555-1212</td>
      <td>77777</td>
    </tr>
  </table>

  </body>
</html>

Nested Loops

The final example will cover nested loops. It builds upon the previous loop code. A nested loop is simply an array element that is in itself another array. If you build arrays like this, you must code your template accordingly. I'll go over an example that simulates the results of a database query.

<loop:results>
  <ul>
  <li><tag:results[].name />
  <li><tag:results[].pass />
    <ul>
      <loop:results[].colors>
        <li><tag:results[].colors[] /></li>
      </loop:results[].colors>
    </ul>
  </ul>
</loop:results>

That may seem a bit confusing at first, but consider the structure of the array we will be assigning to the results tag.

$array = array(
  0 => array(
    'name' => 'Brian',
    'pass' => 'secret',
    'colors' => array(
      0 => 'red',
      1 => 'green',
      2 => 'blue'
    )
  ),
  1 => array(
    'name' => 'Mike',
    'pass' => 'freak',
    'colors' => array(
      0 => 'orange',
      1 => 'yellow',
      2 => 'black'
    )
  )
);

The "base" array, if you will, is a numerically indexed array. Each index contains another array, this time an associative array. Further, each of the two associative arrays contain yet another numerically indexed array (called colors). bTemplate will loop through all of these, provided you have your template set up correctly. From the previous array and template, the resulting HTML will look like this.

<ul>
  <li>Brian
  <li>secret
  <ul>
    <li>red
    <li>green
    <li>blue
  </ul>
</ul>
<ul>
  <li>Mike
  <li>freak
  <ul>
    <li>orange
    <li>yellow
    <li>black
  </ul>
</ul>

Conditionals

Conditionals are simple "if" statements that allow you to conditonally display part of a template. If you have previously written an "is_logged_in()" function that returns TRUE or FALSE, you could use this in your template as follows.

if.php

<?php
  $tpl->set('is_logged_in', is_logged_in(), TRUE);
?>

Notice the third argument passed to the set() method. You must pass it exactly like that (with 'TRUE'). This third argument tells bTemplate to look for "if" statements referencing that variable.

if.tpl

<if:is_logged_in>
  <p>Welcome, <tag:name /></p> 
<else:is_logged_in>
  You are not logged in.
</if:is_logged_in>

Now, it will only attempt to print what's in the "if" statement if the is_logged_in() function returned TRUE.

Case Loops

Case loops are a bit difficult to explain. They were designed such that you could loop through an array but take different actions based on a 'case' element of said array. This requires you to have a numerically indexed array with each element containing an associative array. This associative array will have whatever data you're looping through, as well as an option 'case' element. default is a reserved case and case is a reserved element name (so don't name any of your data elements 'case').

The steps are fairly simple. First you load up a $cases array (you can name the array anything you want). Then you load up your data array, assigning any element from the $cases array to a 'case' subscript. If you do not assign a case subscript, it will assume the 'default' case. Then you assign the data array and the cases array by using the set_cloop() method. It's not really as difficult as it sounds. Take a look at the code.

case.php:

<?php   $cases = array('color1', 'color2');
  $data[] = array('name' => 'George', 'case' => 'color1');
  $data[] = array('name' => 'Frodo', 'case' => 'color2');
  $data[] = array('name' => 'Freako', 'case' => 'color1');
  $data[] = array('name' => 'Whacked');

  $tpl->set_cloop('data', $data, $cases);
?>

case.tpl:

<cloop:data>
  <case:color1>
    <p><font color="red"><tag:data[].name /></font></p>
  </case:color1>
  <case:color2>
    <p><font color="green"><tag:data[].name /></font></p>
  </case:color2>
  <case:default>
    <p><tag:data[].name /></p>
  </case:default>
</cloop:data>

This loop will produce the following HTML output.

<p><font color="red">George</font></p>
<p><font color="green">Frodo</font></p>
<p><font color="red">Feako</font></p>
<p>Whacked</p>

Case loops can also be used for other things. The most common uses are probably alternating table background colors and setting "selected" rows in a list box, some "checked" boxes in a series, and a "selected" radio button in a list.

Conclusion

These are simply the basics. They are all the features of the template class, although if you check out the Advanced Topics you can learn how to manipulate multiple templates (really not that difficult). Since you are responsible for echoing the contents of the parsed template (through the echo $tpl->fetch('template.tpl'); call), you can pass it as an argument or variable to another template (in the same object or a different one, depending on how you like it).

Shortly, as well, I will have examples of real-world, working programs for download. I also plan to show the source of these pages if I ever have enough time.