Object-Oriented HTML Generation In PHP
Written by Alex Armstrong   
Friday, 27 November 2020
Article Index
Object-Oriented HTML Generation In PHP
Object-oriented approach
PHPQuery

Object-oriented approach

So if generating the HTML is only a slight improvement on mixed HTML/PHP what is the solution?

 

Banner

 

A comon way for programming languages to generate their user interfaces, and after all HTML is the user interface for PHP, is to create objects for each type of user interface control that can be used.

For example, if you want to create an HTML button you first create a Button class complete with a range of properties corresponding to the attributes of a button.

To create a button in HTML you would simple create an instance of the button class, set its properties and finally invoke a RenderToHTML method to actually generate the HTML.

Alternatively if you wanted to avoid the need to use a Render method you could insist that all of the properties had to be set as part of the constructor and simply generate the HTML as part of the object's creation.

The problem with this approach is that once the HTML has been generated there is no way of propagating any changes to the object into the HTML - at least a render method means you can re-render the HTML.

For example a very basic class for a button would be something like:

class Button {
 public $value;
 public $width;
 public function RenderHTML(){
  return '<input type="button" value="'.
          $this->value.'" style="width:'.
          $this->width.'px" />';
 }    
}

At this point you might very well complain that this is no improvement - the HTML in string form is still needed.

This is true but the advantage of the approach isn't in the creation of the class, it is in its use.

For example, once you have the Button class you can create as many buttons as you like in your PHP code without any sign of HTML mixed in or in string form:

$Mybutton= new Button();
$Mybutton->value="My Button";
$Mybutton->width="150";

Of course the setting of the attributes could have been done in the constructor and we could have set default values for them and a range of other attributes.

Finally when the button is required to be made part of the HTML page that the PHP is creating all you have to do is something like:

echo $Mybutton->RenderHTML();

which outputs:

<input type="button"
       value="My Button"
       style="width:150px" />

Of course the Render method could include the echo and make the task even simpler - but less flexible.

The point is if you have a suitable library of HTML classes then you can write PHP programs that use them and there is no mixing of HTML and PHP and there is no visible HTML anywhere in the part of the program you are actually writing.

If you adopt this approach the HTML generation part of you PHP programs will be much simpler to understand and maintain.

The problem is finding a suitable library and the temptation is to write your own.

The bad news is that while there were a number of PHP object oriented HTML generator projects they all seem to have died. 

HTML

DOM Generation

There is another way to generate HTML without any HTML at all.

On the other side of the transaction, client side Javascript often manages to do without HTML by working with the DOM.

On the server side there is no DOM for the page because the page is still being built. However, the fact that there is no DOM doesn't stop us from creating one using the standard PHP DOM classes - yes PHP has classes for working with the DOM.

The idea is to create a DOM that represents the page or part of the page by creating and adding elements to a DOM document object. Then generating the HTML is just a matter of using the DOM object's render methods. 

For example, using the DOM approach we can easily create the button used in the previous examples.

First we need a document object to build up:

$html=new DOMDocument('1.0','iso-8859-1' );
$html->formatOutput = true;

The constructor gives the XML version number and the character encoding. Setting formatOutput to true forces the rendering method to indent.

Next we need to create a button or rather input element that can be customised to a button:

$elem=$html->createElement('input');

The create method creates a writeble node unlike the DOMelement constructor which creates a read-only node. Following the creation of the input element we can set attributes:

$elem->setAttribute('type','button');
$elem->setAttribute('value','My Button');
$elem->setAttribute('style','width:125px');

Finally we add the element to the DOM:

$html->appendChild($elem);

Following this we can create additional elements and insert them into the DOM into the correct position.

Once the DOM is complete we can render it to HTML using:

echo html_entity_decode($html->saveHTML());

which produces:

<input type="button"
       value="My Button"
       style="width:125px">

Notice that all of this is achieved using nothing but standard PHP and standard PHP classes.

This approach should be very familiar to any client side programmer. 

New DOMElements

Of course it would look better with the button wrapped in a new class but this is where things start to get difficult.

The logical way to do things is to extend DOMElement. For example:

class Button extends DOMElement{
 function __construct(){
  parent::__construct('input');
  $this->setAttribute('type','button');
 }
}

but this fails for a number of reasons but mainly because a DOMElement created using the constructor is read only. This means that any attempt to set attributes after creation fails.  

What this means is that you have to create any new DOMElements in association with a DOMDocument and this makes building a clean object-oriented hierarchy difficult.

The only reasonable approach is to create a new class that extends DOMDocument and then write methods which create all of the elements you need. For example:

class HTML extends DOMDocument{
 function __construct(){
  parent::__construct('1.0','iso-8859-1' );
  $this->formatOutput = true;
 }

By overriding the constructor we have a class better suited to HTML.

Next we need a new create method:

public  function createButton(){
 $temp= $this->createElement('input');
 $temp->setAttribute('type','button');
 return $temp;
}

We don't have to, but we might as well, override the Save method to ensure the encoding is correct:

public  function saveHTML(){
 return  html_entity_decode(parent::saveHTML());
}

Now we can use the new class to create the standard button example:

$HTML=new HTML();
$elem=$HTML->createButton();
$elem->setAttribute('value','My Button');
$elem->setAttribute('style','width:125px');
$HTML->appendChild($elem);
echo $HTML->saveHTML();

You can add other create methods and other helper methods as required. It isn't difficult but it really shouldn't be necessary.

There should be a good off-the-shelf solution and perhaps there is or should that be was...

 

Banner

<ASIN:1590599098>

<ASIN:0321336577>

<ASIN:0596101015>

<ASIN:1430227273>

<ASIN:0596006306>

<ASIN:032152599X>



Last Updated ( Friday, 27 November 2020 )