I explained earlier a few things about writing reusable CSS code, and how it interacted with PHP. Let’s start with this basic HTML for generating two columns, with the right one being flexible and resizing to fill all available space:
<div class="col2"> <div class="col2-l"> [Content of left column] </div> <div class="col2-r"> <div class="col2-ri"> [Content of right column] </div> </div> <div class="clearer"></div> </div> .col2 { } .col2-l { float: left ; padding: 0 ; margin: 0 ; width: 120px } .col2-r { padding: 0 0 0 120px ; margin: 0 ; width:auto } .col2-ri { float: left ; width : 100% } .clearer { clear: both }
Elementary PHP
How does this translate to PHP? Basically as a series of constants (plus documentation detailing what the column HTML should look like):
class CSS_Col2
{
const ROOT = "col2";
const LEFT = "col2-l";
const RIGHT = "col2-r";
const RIGHT_INNER = "col2-ri";
}
This serves both as documentation for the existence of this component, and as an entry in the auto-completion tool to avoid typing incorrect classes by mistake. However, you still have to get the actual code right:
<div class="<?=CSS_Col2::ROOT?>">
<div class="<?=CSS_Col2::LEFT?>">
[20 lines of left column here]
</div>
<div class="<?=CSS_Col2::RIGHT?>">
<div class="<?=CSS_Col2::RIGHT_INNER?>">
[40 lines of right column here]
</div>
</div>
<?CSS::CLEARER?>
</div>
Did I write everything correctly? Did I forget or misplace a clearer? Forgetting about the inner container in the right column is an easy mistake, and you won’t notice it until you put a clearing element in that column. And if your script is long enough, you won’t be able to see which opening tag matches which closing tag. Surely there must be a way to improve this.
Using HTML constants
A possibility is using constants to contain the relevant HTML:
class CSS_Col2
{
// as above ...
const _BEGIN_LEFT = '<div class="col2"><div class="col2-l">';
const _BEGIN_RIGHT = '</div><div class="col2-r"><div class="col2-ri">';
const _END = '</div></div><div class="clearer"></div>';
}
This makes code shorter, and you can’t mismatch or misplace tags as easily:
<?=CSS_Col2::_BEGIN_LEFT?> [20 lines of left column here] <?=CSS_Col2::_BEGIN_RIGHT?> [40 lines of right column here] <?=CSS_Col2::_END?>
However, all benefits of a nice and clean HTML editor are lost, because HTML constants don’t react as code, and there is therefore no validation performed. At least Eclipse could detect mismatching open/closing tags on raw HTML. Now, if you forget to “_END” your columns, your life is pain.
Using helpers
A common technique is to use a helper function for such rendering tasks. The function accepts some arguments that let it configure what ought to be displayed, then renders the wrapper HTML and inserts the data. Staying within the previous code:
class View_Helper_Col2
{
static function Render($left, $right)
{
?>
<div class="<?=CSS_Col2::ROOT?>">
<div class="<?=CSS_Col2::LEFT?>">
<?php call_user_func($left); ?>
</div>
<div class="<?=CSS_Col2::RIGHT?>">
<div class="<?=CSS_Col2::RIGHT_INNER?>">
<?php call_user_func($right); ?>
</div>
</div>
<?CSS::CLEARER?>
</div><?
}
}
I used callbacks here to do the rendering, because they are the most versatile (it sure beats having to instantiate a “renderable” class for each column). This approach provides the obvious benefit that now the entire rendering is taken care of by a single function, so there is no risk of forgetting or misplacing a tag, and the auto-completion tool can now help check which arguments are provided and in what order.
Still, this means that one should create two functions to render the two columns, and that any necessary data should be made available to them (due to the absence of closures in PHP < 5.3, this often means calling a member function of a view object containing the appropriate data). In the Zend Framework, for instance, one would just write two helpers, and provide them as callbacks knowing that they will have access to the data of the current view:
<?php
$this->render2col(
array($this,'myLeftCol'),
array($this,'myRightCol')
);
?>
Of course, it’s questionable whether moving a three-line for-each loop to a helper of its own actually increases the readability of the code. If defining a new class for every view, there’s the possibility of defining the columns as member functions within that same class, but it’s still somewhat awkward.
Helpers and Closures
PHP 5.3 introduces closures and optional arguments. This means that one can now write the behavior inline:
<?php
$self = &$this;
$this->render2col(
function() use($self)
{
?><h1><?=esc($self->user->name)?></h1><?php
},
function() use($self)
{
?><ul><?php foreach ($self->items as $item): ?>
<li><?php $self->render($item); ?></li>
<?php endforeach; ?></ul><?php
}
);
However, making those functions inline creates a new issue: its not so obvious anymore what exactly a function is doing (because it’s too far away from the original call to the helper function). This can be solved by using a command pattern (while simultaneously noticing that one can get rid of the use keyword by providing $self as an argument (the helper does that):
<?php View_Col2::start($this) ->left(function($view){ ?><h1><?=esc($view->user->name)?></h1><?php }) ->right(function($view){ ?><ul><?php foreach ($view->items as $item): ?> <li><?php $view->render($item); ?></li> <?php endforeach; ?></ul><?php }) ->render();
Labels are now clearly mentioned, allowing empty lines to be inserted to separate the columns without forgetting what they are, so that the code looks cleaner overall.

Recent Comments