[PHP] Try building HTML using DOMDocument class

Aug 27, 2020 PHP PHP7

When building HTML using PHP, I generally think that it is necessary to escape from the echo, here document, or php tag. This time, it's not the only way to output HTML with PHP! It is an article.

As I can tell from the conclusion, it is lacking in practicality, so I hope you will read it with a sense of temperature like “There is also such a method!”.

What is the DOMDocument class?

If you’re a web author, PHP may be a familiar language to some extent, but few may have used the DOMDocument class. Because it’s a class you won’t see unless you do scraping or DOM parsing.

Once again, the DOMDocument class, according to the official description, represents an HTML document or an entire XML document and is the root of the document tree. It means . It is expected to be used in the following cases.

I think this is the place. Also, some people used it to generate XML sitemaps.

Build HTML using DOMDocument

Now, as for the main subject, you can use this DOMDocument method to build HTML. For example, the following code

$dom = new DOMDocument();
$box = $dom->createElement("div");
$text = $dom->createElement("p", "hogehoge");
$box->appendChild($text);
$dom->appendChild($box);
echo $dom->saveHTML();

//Execution result
//<div><p>hogehoge</p></div>

As you can see, you can generate DOM with syntax like JacaScript’s createElement.

By the way, if you want to add class or href, it’s the same as JavaScript.

$box->setAttribute("class", "wrapper"); // add class
$link->setAttribute("href", "http://example.com"); // Add href

It is difficult to use, so try creating a class for DOM generation

By the way, however, it is necessary to add a class in the actual WEB production site, so if it is as it is, generating HTML will be quite troublesome. I don’t know who gets it, but let’s make it easier to use.

class PHPDOM
{
    public function __construct()
    {
        $this->doc = new DOMDocument('1.0','UTF-8');
    }

    public function setNode(string $tagName, ?string $className = null, ?string $text = null): object
    {
        $node = $this->doc->createElement($tagName, $text);
        if (!empty($className)) {
            $node->setAttribute("class", $className);
        }

        return $node;
    }

    public function a(string $href, ?string $className = null, ?string $text = null): object
    {
        $node = $this->doc->createElement("a", $text);
        if (!empty($className)) {
            $node->setAttribute("class", $className);
        }
        $node->setAttribute("href", $href);

        return $node;
    }

    public function img(string $src, ?string $className = null): object
    {
        $node = $this->doc->createElement("img");
        if (!empty($className)) {
            $node->setAttribute("class", $className);
        }
        $node->setAttribute("src", $src);

        return $node;
    }

    public function generator(object $obj):void
    {
        $this->doc->appendChild($obj);
        echo $this->doc->saveHTML();
    }
}

By doing this, you can slim down to some extent even when using class or tags that need special attributes. For example, you can use it as follows.

$array = [
    "hoge" => "https://hoge.com",
    "fuga" => "https://fuga.com",
    "piyo" => "https://piyo.com"
];

$dom = new PHPDOM();
$list = $dom->setNode("ul", "list"); // create <ul class="list"></ul>

foreach ($array as $name => $url) {
    $item = $dom->setNode("li", "list-item"); // create <li class="list-item"></li>
    $item->appendChild($dom->a($url, "list-item__link", $name)); // put a tag in li
    $list->appendChild($item); // put li in ul
}
$dom->generator($list); // echo $list as HTML


//Execution result
// <ul class="list">
// <li class="list-item"><a class="list-item__link" href="https://hoge.com">hoge</a></li>
// <li class="list-item"><a class="list-item__link" href="https://fuga.com">fuga</a></li>
// <li class="list-item"><a class="list-item__link" href="https://piyo.com">piyo</a></li>
// </ul>

Benefits of using DOMDocument

From the perspective of a person who sees it for the first time, it is supposed to be “What’s this!”, so it is not suitable for development with a large number of people, but it is not without merit! …Perhaps

No need to go outside the ###php tag For example, with WordPress, I think the following code is a fairly familiar syntax.

<?php if ($query->have_posts()): ?>
<section class="wrapper">
    <?php
    while ($query->have_posts()):
        $query->the_post();
    ?>
    <div class="item">
        <p class="title"><?=get_the_title()?></p>
    </div>
    <?php endwhile; ?>
</section>
<?php endif; ?>

The php and html tags are confusing and hard to see! If you use DOMDocument, you can refresh (?) as follows.

<?php
if ($query->have_posts()){
    $dom = new PHPDOM();
    $sec = $dom->setNode('section', "wrapper");
    while($query->have_posts()){
        $item = $dom->setNode("div", "item");
        $item->appendChild($dom->setNode("p", "title", get_the_title()));
        $sec->appendChild($item);
    }
    $dom->generator($sec);
}
?>

It seems that you can fall into the illusion that it is refreshing with more cluttered code that echoes by checking the presence of thumbnails and the presence of custom fields! There is no word in my dictionary that you can write beautifully by using heredoc without having to go outside! (confusion)

less typos

When coding with BEM, there should be many people who were addicted to typos in the class name.

BEM is a notation that fixes the naming convention of class like <div class="block__element--modifire"> to make coding in SCSS particularly easy, but if you make a typo in html, you can specify It may take some time.

To prevent such a typo, you may want to do something like this.

if ($query->have_posts()){
    $class = "list";
    $dom = new PHPDOM();
    $sec = $dom->setNode('section', $class);
    while($query->have_posts()){
        $item = $dom->setNode("div", "{$class}__item");
        $item->appendChild($dom->setNode("p", "{$class}__item-title", get_the_title()));
        $sec->appendChild($item);
    }
    $dom->generator($sec);
}

There is an easier way to write it, though…

PerformanceAs for performance, needless to say, it’s bad. It is overwhelmingly faster to echo normally. It is a story that how many function calls are made to make one div. (Crying)

The larger the DOM, the more variables there are, and I’ve seen an article that regular expressions are faster than DOMDocument for DOM parsing. (*Verification required)

Conclusion: There is no need to use it, but there is one way (?)

Well, I wrote a lot, but I think that if there is a here document or ternary operator normally, there is no need to put it out of the php tag and there will be few typos in the class name, so use it purposely There may not be any benefit.

In the first place, frameworks like React and Vue are popular because the createElement method is difficult to use even in the JS neighborhood, and I think it is better to use a widely-used syntax than PHP with an unclear syntax.

However, if you are creating a personal site, it may be possible to use it, so please be sure to mention DOMDocument.