Wrapping HTML in PHP

  • Reading time: 3 min
  • Published 4 years ago

Among other things, I am currently working on rewriting the text handling code of this website into something cleaner and more usable. In the current version, the text manipulation is a big non-deterministic ugly mess of regular expressions and other not-so-niceties. For the new version I decided on going with a modular approach and - more importantly - doing the actual replacements I want to apply to the Markdown before showing it with DOM manipulations.

One of the wonderful but often forgotten features of PHP's DOM library is that it offers the DOMDocumentFragment not-quite-standard part of the DOM Level 1 spec. John Resig once wrote a wonderful piece on the JavaScript version of this. As John points out, working with fragments can lead to significant performance improvements. I have to admit that I did not conduct performance testing to conclusively say that this also applies to PHP but it at least feels faster. Additionally, these fragments don't come with all the garbage of full blown HTML documents that the default DOMDocument tends to deliver.

In the case of having HTML stored in a string variable, wrapping things is almost too easy:

$html = "<p>I will be wrapped</p>"; $html = "<div>".$html."</div>";

I bet you wrote code like that at least once. Regardless of the programming language. But this is not good code. To me, the most obvious flaw is the possibility to miss things. What if you forget the slash in the second div. Happened to the best of us. Followed by hours of trying to find out why there's suddenly this weird gap in the page.

When manipulating HTML inside the DOM classes, malformed output cannot happen. Exceptions can, but that's the point. You'll know when something goes wrong before you already shipped it to the client. Unfortunately, working with objects usually means a little more code than string manipulation. In return, the code allows for telling a better readable story.

The below code snippet is extracted from the above mentioned text manipulation library I am working on. Once finished (which hopefully happens in the coming days/weeks), this will be available on GitHub. There will of course be a Laravel integration. The presented method accepts a node (which technically already could contain children) in which the given fragment will be wrapped. Poof, magic. Requires PHP >=5.4, though.

protected function wrapFragment(DOMDocumentFragment $fragment, DOMNode $wrapNode)
{
    $newFragment = $this->doc->createDocumentFragment();
    $wrapNode->appendChild($fragment->cloneNode(true));
    $newFragment->appendChild($wrapNode);

    return $newFragment;
}