Ambrosius Topor

Notiz — 2020-04-19

Single File Components in PHP

The Pattern in Vue

One of the nicest things about Vue is its concept of Single File Components (SFCs). For me, I started with templates created by strings, as I didn't want to jump right in with the full compilation/transpilation setup (using Vue CLI/UI or Webpack, etc.):

const MoneyDashboard = {
    template: `
        <article class="dashboard">
            <h1>Dashboard</h1>
        </article>
    `
}

But once you have your setup done, you don't really want to go back writing components in that way (not having support for syntax highlighting being the most obvious drawback). Refactored to an SFC, it looks like this (excerpt):

<template>
    <article class="dashboard">
        <h1>Dashboard</h1>
    </article>
</template>
<script>
export default {
}
</script>

Application to PHP

As I like the concept—following a components based approach and have logic and views nearby, but still separated and for sure not generated by string manipulation or creation by using the DOMElement class)—I wanted to also use this in PHP. I've remembered there was something used in PHAR files, which I could utilize to reach the goal.

This is what I came up with so far:

<?php
class Paragraph extends Component
{
    public function render()
    {
        // Component data
        $data = [
            'heading' => 'An Example',
            'body' => 'Lorem ipsum',
        ];

        // Get template
        $fp = fopen(__FILE__, 'r');
        fseek($fp, __COMPILER_HALT_OFFSET__ + 4);
        $template = fread($fp, 4096);

        // Prepare/clean up template
        $template = str_replace('<template>', '', $template);
        $template = str_replace('</template>', '', $template);
        $template = trim($template);

        return $this->renderTwig($template, $data);
    }
}
__halt_compiler();
?>
<template>
    <section>
        <h1>{{ heading }}</h1>
        <p>{{ body }}</p>
    <section>
</template>

Keep in mind that this is just a proof of concept—the handling of the template element should be improved as well as the hard-coded seeking to skip the PHP end tag (which in this way only works if you are disciplined and save your file with "\r\n" line endings).

Some problems/thoughts on this:

While the components I'm using in a project at hand are quite simple and the template files look ridiculous (looking at their size), I'm not sure to really migrate to this pattern.

Approach to conform to existing formats

Taking this a bit further into a standardized "web components" style format, it could look like this:

<script type="application/php">
class Paragraph extends Component
{
    public function render() { /* */ }
}
</script>
<template lang="twig">
    <section>
        <h1>{{ heading }}</h1>
        <p>{{ body }}</p>
    <section>
</template>

References

Comments

There are no comments yet.

Thanks for your contribution!
Your comment will be visible once it has been approved.

An error occured—please try again.

Add Comment