You are hereHome / Development / PHP Printer Pattern
PHP Printer Pattern
Update: Wrong link updated.
After starting a spare time PHP project a while ago, I ran into several problems, because I didn't respect my programming language. As soon as I realized I'm moving into trouble, I sat back, started thinking about how to get the project back under my control, and finally came up with some PHP design patterns.
The first problem I started with was how to seperate static and dynamic parts of all the pages in a clean, readable and simple manner. After a while, I got my code to look somewhat like this:
<?php
require_once "page.inc.php";
page_printBegin();
printHead();
page_printBody();
$myParam = isset($_GET["param"]) ? $_GET["param"] : 0;
if ($myParam < 1 || $myParam > 3)
{
// 'param' must be between 1 and 3
print "<p class=\"error\">Param must be between 1 and 3</p>";
}
else
{
printBody();
}
page_printEnd();
exit;
function printHead()
{
print "<title>Cool page</title>";
}
function printBody($param)
{
print "<h1>Param is $param</h1>";
}
?>
As you may guess, the included file "page.inc.php" contains several functions to print portions of static html code, where "page_printBegin" prints the doctype, head, encoding etc, "page_printBody" prints the closing head tag, the body tag and stuff like the page's head line. "page_printEnd" last not least contains the sidebar and the closing body tag.
As you may figure out, this approach has several disadvantages:
- There are redundances, because the three page printing functions are to be called on each page.
- (Pre)processing code and outputting code are mixed up.
Let's take a closer look on what's happening here: We obviously deal with some kind of algorithm (invoke page_printBegin(), invoke printHead(), invoke page_PrintBody(), invoke printBody()...), whereas a large part of it stays the same, while another part changes from page to page. If you are familiar with Design Patterns, you may know that there are two ways of handling such a case: The template method pattern and the strategy pattern.
In this case I decided to use the strategy pattern. The reason for this is, that the same pattern I introduce for printing pages will be applied for forms and tables later one, so I could possibly end up in multiple inheritence if I rely on the template method pattern. And I definitly don't want that!
The trick is simple. First I created a class called "PagePrinter" and an according Interface IPageContentPrinter. They do the work. For convenience, I added an IPageContentPrinter implementation for handling errors right away, and create a function to invoke it. This is how it looks:
<?php
require_once "page.inc.php";
class PagePrinter
{
/**
* Static. Prints a page delegating to $contentPrinter
*
* $contentPrinter must provide two functions printHead()
* and printBody(), both of which return void.
*
* @param IPageContentPrinter
* @return void
*/
function printPage($contentPrinter)
{
page_printBegin();
$contentPrinter->printHead();
page_printBody();
$contentPrinter->printBody();
page_printEnd();
}
/**
* Static. Prints an error page
*
* @param String The error message
* @return void
*/
function printErrorPage($message)
{
PagePrinter::printPage(
new ErrorPageContentPrinter($message));
}
}
class IPageContentPrinter
{
function printHead() {}
function printBody() {}
}
class ErrorPageContentPrinter extends IPageContentPrinter
{
var $message;
function ErrorPageContentPrinter($message)
{
$this->message = $message;
}
function printHead()
{
print "<title>Error</title>";
}
function printBody()
{
print "<p class=\"error\">".$this->message."</p>";
}
}
?>
The idea should be pretty clear. The function printPage() on PagePrinter implements the algorithm, delegating the changing parts to the class passed as a parameter. Since PagePrinter has no state, I made all its functions static. ErrorPageContentPrinter demonstrates how it works.
Note, that if for example I decide to have a flexible menu or side bar, I can just add a function printSideBar() to IPageContentPrinter, invoke it in the printPage() functions and overload it whereever suitable.
Back to the original page. After applying the page printer and cleaning up a little bit, it now looks like this:
<?php
require_once "pageprinter.inc.php";
class MyPage extends IPageContentPrinter
{
var $param;
function main()
{
$this->param = isset($_GET["param"]) ?
$_GET["param"] : 0;
if ($this->param < 1 || $this->param > 3)
{
PagePrinter::printErrorPage(
"Param must be between 1 and 3");
}
else
{
PagePrinter::printPage(&$this);
}
}
function printHead()
{
print "<title>Cool page</title>";
}
function printBody()
{
print "<h1>Param is ".$this->param."</h1>";
}
}
$page = new MyPage();
$page->main();
exit;
?>
Wonder why the code invoking the page is at the end? It's definitely ugly, but necessary due to a really weird PHP behaviour. For some reasons, PHP has trouble with the extends keywords. See that this works:
<?php
$temp = new A();
class A {}
?>
But it leads to trouble if A inherits. The following code yields a compiler error saying class A was not defined:
<?php
require_once "B.inc.php";
$temp = new A();
class A extends B {}
?>
Wonder why, actually... I presume it is a bug and PHP 5 works better. However, it may be acceptable, 'cause it's just stupid code that resides on each page. Real things start in main(). Let's look at the advantages of using a page printer:
- Redundance is gone. Each page only needs to implement what is specific, everything else is wrapped up in the PagePrinter class.
- Preprocessing is done in the main() functions, while outputting is done in printHead(), printBody(), and the PagePrinter itself.
- I personally prefer having a main() function...
To see the page printer alive visit the examples page. You can also browse the source code over there.
To be contiued: Stuffing form and table handling into printer classes.


You must send a HTTP header, like described in this tutorial:
<?php/* Redirect browser */
header("Location: http://www.example.com/");
/* Make sure that code below does not get executed when we redirect. */
exit;
?>
hey ive been messing around with ezpdf and fpdf. i managed to create the pdf file eventually, but i cant make the print dialog auto appear. any idea how this can be done?