Hey everyone! I’m Maxim Akimov, a full-stack web developer, co-founder of the WPLake agency and lead developer of the Procaptcha WordPress integration.

I’m excited to announce the release of PHP Views, a Composer package recently created while working on the Procaptcha WordPress integration.

1. What is PHP Views?

PHP Views is a lightweight, standalone Composer package designed to simplify templating in PHP. The package introduces a model-driven approach, supports multiple namespaces, and includes a custom Blade implementation as the default template engine.

While many PHP frameworks come with their own solutions for views, there are countless PHP projects without a templating system (including CMS, like WordPress). Writing pure PHP templates can be cumbersome and error-prone. PHP Views aims to make templating simple, flexible, and accessible to anyone.

You might be wondering: “What about Symfony’s Twig? It’s already available as a standalone package!”

That’s true, and Twig is a great tool. However, Twig focuses primarily on the templating side of views. While it allows you to create clean templates, it lacks support for models, leaving developers to rely on plain array keys for passing data.

The model-driven approach in PHP Views bridges this gap by bringing the benefits of object-oriented programming to templates. Models provide:

  • Typed variables for better reliability.
  • Methods for encapsulating logic within models.
  • Fewer errors caused by typos, which often become headaches when working with untyped array keys.

Another point worth mentioning is that, unlike Blade, Twig doesn’t support plain PHP functions or code. This means you need to learn its specific function and filter names, which can be an extra hurdle for PHP developers.

No holy wars – just options

Every tool has its pros and cons. I’ve been using Twig myself for years and deeply appreciate the solutions it provides. However I clearly see the room for improvement, and Model’s conception from the PHP Views package may make your Twig experience much better.

1.2) Freedom to choose your template engine

Returning to PHP Views: the package includes a custom Blade compiler and uses it as the default template engine. However, flexibility is key. You can integrate Twig, or any other template engine, with just a few lines of code while still enjoying the benefits of the model-driven approach and other features that PHP Views brings to the table.

1.3) Notes on the standalone Blade implementation

Blade is an elegant and powerful template engine originally developed for Laravel. Unlike Twig, Blade embraces PHP usage rather than restricting it. It enhances templates with syntax sugar (which we all love), making them clean and easy to read.

Blade introduces special shorthand tokens that simplify the most cumbersome syntax constructions, while still being fully-fledged PHP with access to all its functions and capabilities.

Unfortunately, Blade isn't available as a standalone package, so this package includes its own Blade compiler. It provides full support for Blade's key features while remaining completely independent of Laravel.

You may have come across packages that attempt to adapt the official Blade engine by creating stubs for its Laravel dependencies, such as the jenssegers/blade package. However, we chose not to adopt this approach for several reasons:

  • PHP Version Requirements: It mandates PHP 8.2 or higher.
  • External Dependencies: It introduces additional external dependencies.
  • Potential Breakage: It can become unstable with future Laravel updates (as demonstrated by past incidents).
  • Limited Flexibility: Since it wasn’t designed as a standalone component, it lacks some of the customization abilities.
  • Global functions: Laravel's implementation includes global helper functions, which becomes a problem when you need to scope the package.

Thanks to the great Blade's conceptual design, our compiler implementation required fewer than 200 lines of code.

2. Package Benefits

Before diving into the concept and implementation, let’s take a look at what this package has to offer:

  • Blazing fast: Outperforms the original Laravel Blade (see the benchmark below).
  • Zero Dependencies: Lightweight and easy to integrate into any project.
  • Wide Compatibility: PHP 7.4+, 8.0+
  • SOLID architecture: Designed with flexibility in mind, allowing you to easily override modules to meet your specific requirements
  • Namespace Support: Seamlessly manage multiple templates under a unified, structured approach.
  • Reliable: Thoroughly tested with Pest and checked by PHPStan.

While the list may not seem overly fancy, the real strength of this package lies in its flexibility. With PHP Views, you’re free to use it in a way that best fits your project:

  • As a Views provider: Combine a model-driven approach with the built-in Blade engine for clean, dynamic templates.
  • As a standalone Blade engine: Use its custom Blade implementation for your Blade-based templates.
  • For Model-Driven Flexibility: Leverage the model-driven approach with any template engine, such as Twig or even pure PHP.
  • As a Template Connector: Integrate and unify templates that utilize different engines under one system.

2.1) Benchmark

We conducted a PHP performance benchmark to compare this package with Laravel's Blade (mocked using jenssegers/blade) and Twig. Here are the results for 1000x renders:

ContestantFirst Rendering, MSCached Rendering, MS
prosopo/views (without models)19.7519.75 (no cache atm)
prosopo/views (with models)43.7843.78 (no cache atm)
illuminate/view (Blade from Laravel)181.2456.77
twig/twig441.139.47

The numbers speak for themselves. In uncached rendering, even with model class-related overhead, PHP Views’ implementation significantly outperforms all competitors. While Twig offers a robust caching solution, PHP Views still delivers better performance even than Laravel’s Blade engine with caching.

Note: we used the following package versions:

Since the benchmark is included in the package repository, you can easily run it locally to verify the results:

  1. git clone https://github.com/prosopo/php-views.git
  2. composer install; cd benchmark; composer install
  3. php benchmark {1000} - pass your renders count

3. Installation and minimal usage

3.1) Installation

PHP Views is distributed as a Composer package, making installation straightforward:

composer require prosopo/views

After installation, ensure that your application includes the Composer autoloader (if it hasn’t been included already):

require __DIR__ . '/vendor/autoload.php';

3.2) Minimal setup

To get started, you’ll need to create three instances: ViewTemplateRenderer, ViewNamespaceConfig, and ViewsManager.

The main configuration takes place in ViewNamespaceConfig, where you define the folder for your templates and the root namespace for the associated models.

use Prosopo\Views\View\ViewNamespaceConfig;
use Prosopo\Views\View\ViewTemplateRenderer;
use Prosopo\Views\ViewsManager;

require __DIR__ . '/vendor/autoload.php';

// 1. Make the Template Renderer.
// (By default it uses the built-in Blade, but you can connect any)

$viewTemplateRenderer = new ViewTemplateRenderer();

// 2. Make the namespace config

$namespaceConfig = (new ViewNamespaceConfig($viewTemplateRenderer))
    ->setTemplatesRootPath(__DIR__ . './templates')
    ->setTemplateFileExtension('.blade.php');

// 3. Make the Views Manager instance:

$viewsManager = new ViewsManager();

// 4. Add the root namespace of your Template Models

$viewsManager->registerNamespace('MyPackage\Views', $namespaceConfig);

3.3) Model definition

Now you're ready to create your first model. Similar to many frameworks, such as Laravel, this package embraces a model-driven approach to templates.

Each template is paired with its own Model, where the Model's public properties and methods act as arguments available within the template.

Model class must extend the BaseTemplateModel class or implement the TemplateModelInterface:

namespace MyPackage\Views;

use Prosopo\Views\BaseTemplateModel;

class EmployeeTemplateModel extends BaseTemplateModel
{
    public int $salary;
    public int $bonus;
    public CompanyTemplateModel $company;

    public function total(): int
    {
        return $this->salary + $this->bonus;
    }
}

Model template (Blade is used in this example):

<p>
  Your month income is {{ $total() }},
  from which {{ $salary }} is a salary, and {{ $bonus }} is a bonus.
  Est. taxes: {{ $company->calcTaxes($salary) }}
</p>

<p>Company info:</p>

{!! $company !!}

As you can see, all the public properties of the model are accessible within the template, including nested models like $company. This also enables you to call their public methods directly within the template.

The BaseTemplateModel class which we inherited overrides the __toString() method, allowing inner models to be rendered as strings using Blade echo statements with the HTML support. For instance:

{!! $innerModel !!} part of the template will render the model and print the result.

Naming clarification: this package does not require the Model suffix in the names of model classes. In this article, we use the Model suffix for class names purely for demonstration purposes.

3.4) Automated templates matching

The built-in ModelTemplateResolver automatically matches templates based on the Model names and their relative namespaces. This automates the process of associating templates with their corresponding Models.

Example:

  • src/
    • Views/
      • Homepage.php
      • Settings
        • GeneralSettings.php
    • templates/
      • homepage{.blade.php}
      • settings/
        • general-settings{.blade.php}

We define the root templates folder along with the models root namespace in the ViewsNamespaceConfig (as we already did above):

$namespaceConfig = (new ViewNamespaceConfig($viewTemplateRenderer))
    ->setTemplatesRootPath(__DIR__ . './templates')
    ->setTemplateFileExtension('.blade.php');

// 3. Make the Views Manager instance:

$viewsManager = new ViewsManager();

// 4. Add the root namespace of your Template Models

$viewsManager->registerNamespace('MyPackage\Views', $namespaceConfig);

Naming Note: Use dashes in template names, as camelCase in Model names is automatically converted to dash-separated names.

3.5) Usage

The ViewsManager instance (which we created during the setup) provides the createModel and renderModel methods.

You can create, set values, and render a Model in a single step using the callback argument of the renderView method, as shown below:

echo $viewsManager->renderModel(
    EmployeeTemplateModel::class,
    function (EmployeeTemplateModel $employee) use ($salary, $bonus) {
        $employee->salary = $salary;
        $employee->bonus = $bonus;
    }
);

This approach enables a functional programming style when working with Models.

Multi-step creation and rendering

When you need split creation, call the makeModel method to create the model, and then render later when you need it.

$employee = $viewsManager->createModel(EmployeeTemplateModel::class);

// ...

$employee->salary = $salary;
$employee->bonus = $bonus;

// ...

echo $views->renderModel($employee);

// Tip: you can pass the callback as the second argument for both createModel() and renderModel() models
// to customize the Model properties before returning/rendering. 

References Advice

The ViewsManager class implements three interfaces:

  1. ViewNamespaceManagerInterface for registerNamespace
  2. ModelFactoryInterface for createModel
  3. ModelRendererInterface for renderModel

When passing the ViewsManager instance to your methods, use one of these interfaces as the argument type instead of the ViewsManager class itself.

This approach ensures that only the specific actions you expect are accessible, promoting cleaner and more maintainable code.

That's it! You’re now ready to start using the package.

4. Afterwords

This was a quick overview of the PHP Views package, created to simplify templating in PHP. For more details on advanced configuration, module overriding, and additional features, check out the official repository.

Thank you for reading — we hope this package makes your development experience smoother and more enjoyable. We’d love to hear your feedback and see how you integrate it into your projects. Contributions are always welcome!

P.S. If you find PHP Views worth your attention, we’d greatly appreciate it if you gave its GitHub repository a star and shared it with your colleagues.


Related Posts to PHP Views Package - Templating Made Easy with Blade and Model-Driven Approach

Ready to ditch Google reCAPTCHA?
Start for free today. No credit card required.