Skip to content
  • About
    • What is Symfony?
    • Community
    • News
    • Contributing
    • Support
  • Documentation
    • Symfony Docs
    • Symfony Book
    • Screencasts
    • Symfony Bundles
    • Symfony Cloud
    • Training
  • Services
    • SensioLabs Professional services to help you with Symfony
    • Platform.sh for Symfony Best platform to deploy Symfony apps
    • SymfonyInsight Automatic quality checks for your apps
    • Symfony Certification Prove your knowledge and boost your career
    • Blackfire Profile and monitor performance of your apps
  • Other
  • Blog
  • Download
sponsored by SensioLabs
  1. Home
  2. Documentation
  3. Templating
  4. How to Use PHP instead of Twig for Templates
  • Documentation
  • Book
  • Reference
  • Bundles
  • Cloud

Table of Contents

  • Rendering PHP Templates
  • Decorating Templates
  • Working with Slots
  • Including other Templates
  • Embedding other Controllers
  • Using Template Helpers
    • Creating Links between Pages
    • Using Assets: Images, JavaScripts and Stylesheets
    • Profiling Templates
  • Output Escaping

How to Use PHP instead of Twig for Templates

Edit this page

Warning: You are browsing the documentation for Symfony 3.2, which is no longer maintained.

Read the updated version of this page for Symfony 6.2 (the current stable version).

How to Use PHP instead of Twig for Templates

Symfony defaults to Twig for its template engine, but you can still use plain PHP code if you want. Both templating engines are supported equally in Symfony. Symfony adds some nice features on top of PHP to make writing templates with PHP more powerful.

Tip

If you choose not use Twig and you disable it, you'll need to implement your own exception handler via the kernel.exception event.

Rendering PHP Templates

If you want to use the PHP templating engine, first, make sure to enable it in your application configuration file:

  • YAML
  • XML
  • PHP
1
2
3
4
5
# app/config/config.yml
framework:
    # ...
    templating:
        engines: ['twig', 'php']
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- app/config/config.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:framework="http://symfony.com/schema/dic/symfony"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        http://symfony.com/schema/dic/services/services-1.0.xsd
        http://symfony.com/schema/dic/symfony
        http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">

    <framework:config>
        <!-- ... -->
        <framework:templating>
            <framework:engine id="twig" />
            <framework:engine id="php" />
        </framework:templating>
    </framework:config>
</container>
1
2
3
4
5
6
$container->loadFromExtension('framework', array(
    // ...
    'templating' => array(
        'engines' => array('twig', 'php'),
    ),
));

You can now render a PHP template instead of a Twig one simply by using the .php extension in the template name instead of .twig. The controller below renders the index.html.php template:

1
2
3
4
5
6
7
8
9
10
// src/AppBundle/Controller/HelloController.php

// ...
public function indexAction($name)
{
    return $this->render(
        'AppBundle:Hello:index.html.php',
        array('name' => $name)
    );
}

You can also use the @Template shortcut to render the default AppBundle:Hello:index.html.php template:

1
2
3
4
5
6
7
8
9
10
11
12
// src/AppBundle/Controller/HelloController.php
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

// ...

/**
 * @Template(engine="php")
 */
public function indexAction($name)
{
    return array('name' => $name);
}

Caution

Enabling the php and twig template engines simultaneously is allowed, but it will produce an undesirable side effect in your application: the @ notation for Twig namespaces will no longer be supported for the render() method:

1
2
3
4
5
6
7
8
9
10
public function indexAction()
{
    // ...

    // namespaced templates will no longer work in controllers
    $this->render('@App/Default/index.html.twig');

    // you must use the traditional template notation
    $this->render('AppBundle:Default:index.html.twig');
}
1
2
3
4
5
{# inside a Twig template, namespaced templates work as expected #}
{{ include('@App/Default/index.html.twig') }}

{# traditional template notation will also work #}
{{ include('AppBundle:Default:index.html.twig') }}

Decorating Templates

More often than not, templates in a project share common elements, like the well-known header and footer. In Symfony, this problem is thought about differently: a template can be decorated by another one.

The index.html.php template is decorated by layout.html.php, thanks to the extend() call:

1
2
3
4
<!-- app/Resources/views/Hello/index.html.php -->
<?php $view->extend('AppBundle::layout.html.php') ?>

Hello <?php echo $name ?>!

The AppBundle::layout.html.php notation sounds familiar, doesn't it? It is the same notation used to reference a template. The :: part simply means that the controller element is empty, so the corresponding file is directly stored under views/.

Now, have a look at the layout.html.php file:

1
2
3
4
5
6
<!-- app/Resources/views/layout.html.php -->
<?php $view->extend('::base.html.php') ?>

<h1>Hello Application</h1>

<?php $view['slots']->output('_content') ?>

The layout is itself decorated by another one (::base.html.php). Symfony supports multiple decoration levels: a layout can itself be decorated by another one. When the bundle part of the template name is empty, views are looked for in the app/Resources/views/ directory. This directory stores global views for your entire project:

1
2
3
4
5
6
7
8
9
10
11
<!-- app/Resources/views/base.html.php -->
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title><?php $view['slots']->output('title', 'Hello Application') ?></title>
    </head>
    <body>
        <?php $view['slots']->output('_content') ?>
    </body>
</html>

For both layouts, the $view['slots']->output('_content') expression is replaced by the content of the child template, index.html.php and layout.html.php respectively (more on slots in the next section).

As you can see, Symfony provides methods on a mysterious $view object. In a template, the $view variable is always available and refers to a special object that provides a bunch of methods that makes the template engine tick.

Working with Slots

A slot is a snippet of code, defined in a template, and reusable in any layout decorating the template. In the index.html.php template, define a title slot:

1
2
3
4
5
6
<!-- app/Resources/views/Hello/index.html.php -->
<?php $view->extend('AppBundle::layout.html.php') ?>

<?php $view['slots']->set('title', 'Hello World Application') ?>

Hello <?php echo $name ?>!

The base layout already has the code to output the title in the header:

1
2
3
4
5
<!-- app/Resources/views/base.html.php -->
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title><?php $view['slots']->output('title', 'Hello Application') ?></title>
</head>

The output() method inserts the content of a slot and optionally takes a default value if the slot is not defined. And _content is just a special slot that contains the rendered child template.

For large slots, there is also an extended syntax:

1
2
3
<?php $view['slots']->start('title') ?>
    Some large amount of HTML
<?php $view['slots']->stop() ?>

Including other Templates

The best way to share a snippet of template code is to define a template that can then be included into other templates.

Create a hello.html.php template:

1
2
<!-- app/Resources/views/Hello/hello.html.php -->
Hello <?php echo $name ?>!

And change the index.html.php template to include it:

1
2
3
4
<!-- app/Resources/views/Hello/index.html.php -->
<?php $view->extend('AppBundle::layout.html.php') ?>

<?php echo $view->render('AppBundle:Hello:hello.html.php', array('name' => $name)) ?>

The render() method evaluates and returns the content of another template (this is the exact same method as the one used in the controller).

Embedding other Controllers

And what if you want to embed the result of another controller in a template? That's very useful when working with Ajax, or when the embedded template needs some variable not available in the main template.

If you create a fancy action, and want to include it into the index.html.php template, simply use the following code:

1
2
3
4
5
6
7
<!-- app/Resources/views/Hello/index.html.php -->
<?php echo $view['actions']->render(
    new \Symfony\Component\HttpKernel\Controller\ControllerReference('AppBundle:Hello:fancy', array(
        'name'  => $name,
        'color' => 'green',
    ))
) ?>

Here, the AppBundle:Hello:fancy string refers to the fancy action of the Hello controller:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// src/AppBundle/Controller/HelloController.php

class HelloController extends Controller
{
    public function fancyAction($name, $color)
    {
        // create some object, based on the $color variable
        $object = ...;

        return $this->render('AppBundle:Hello:fancy.html.php', array(
            'name'   => $name,
            'object' => $object
        ));
    }

    // ...
}

But where is the $view['actions'] array element defined? Like $view['slots'], it's called a template helper, and the next section tells you more about those.

Using Template Helpers

The Symfony templating system can be easily extended via helpers. Helpers are PHP objects that provide features useful in a template context. actions and slots are two of the built-in Symfony helpers.

Creating Links between Pages

Speaking of web applications, creating links between pages is a must. Instead of hardcoding URLs in templates, the router helper knows how to generate URLs based on the routing configuration. That way, all your URLs can be easily updated by changing the configuration:

1
2
3
<a href="<?php echo $view['router']->path('hello', array('name' => 'Thomas')) ?>">
    Greet Thomas!
</a>

The path() method takes the route name and an array of parameters as arguments. The route name is the main key under which routes are referenced and the parameters are the values of the placeholders defined in the route pattern:

1
2
3
4
# src/AppBundle/Resources/config/routing.yml
hello: # The route name
    path:     /hello/{name}
    defaults: { _controller: AppBundle:Hello:index }

Using Assets: Images, JavaScripts and Stylesheets

What would the Internet be without images, JavaScripts, and stylesheets? Symfony provides the assets tag to deal with them easily:

1
2
3
<link href="<?php echo $view['assets']->getUrl('css/blog.css') ?>" rel="stylesheet" type="text/css" />

<img src="<?php echo $view['assets']->getUrl('images/logo.png') ?>" />

The assets helper's main purpose is to make your application more portable. Thanks to this helper, you can move the application root directory anywhere under your web root directory without changing anything in your template's code.

Profiling Templates

By using the stopwatch helper, you are able to time parts of your template and display it on the timeline of the WebProfilerBundle:

1
2
3
<?php $view['stopwatch']->start('foo') ?>
... things that get timed
<?php $view['stopwatch']->stop('foo') ?>

Tip

If you use the same name more than once in your template, the times are grouped on the same line in the timeline.

Output Escaping

When using PHP templates, escape variables whenever they are displayed to the user:

1
<?php echo $view->escape($var) ?>

By default, the escape() method assumes that the variable is outputted within an HTML context. The second argument lets you change the context. For instance, to output something in a JavaScript script, use the js context:

1
<?php echo $view->escape($var, 'js') ?>
This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.
TOC
    Version
    We stand with Ukraine.
    Version:
    Take the exam at home

    Take the exam at home

    Code consumes server resources. Blackfire tells you how

    Code consumes server resources. Blackfire tells you how

    Symfony footer

    ↓ Our footer now uses the colors of the Ukrainian flag because Symfony stands with the people of Ukraine.

    Avatar of Jérémy DERUSSÉ, a Symfony contributor

    Thanks Jérémy DERUSSÉ (@jderusse) for being a Symfony contributor

    692 commits • 1.55M lines changed

    View all contributors that help us make Symfony

    Become a Symfony contributor

    Be an active part of the community and contribute ideas, code and bug fixes. Both experts and newcomers are welcome.

    Learn how to contribute

    Symfony™ is a trademark of Symfony SAS. All rights reserved.

    • What is Symfony?

      • Symfony at a Glance
      • Symfony Components
      • Case Studies
      • Symfony Releases
      • Security Policy
      • Logo & Screenshots
      • Trademark & Licenses
      • symfony1 Legacy
    • Learn Symfony

      • Symfony Docs
      • Symfony Book
      • Reference
      • Bundles
      • Best Practices
      • Training
      • eLearning Platform
      • Certification
    • Screencasts

      • Learn Symfony
      • Learn PHP
      • Learn JavaScript
      • Learn Drupal
      • Learn RESTful APIs
    • Community

      • SymfonyConnect
      • Support
      • How to be Involved
      • Code of Conduct
      • Events & Meetups
      • Projects using Symfony
      • Downloads Stats
      • Contributors
      • Backers
    • Blog

      • Events & Meetups
      • A week of symfony
      • Case studies
      • Cloud
      • Community
      • Conferences
      • Diversity
      • Documentation
      • Living on the edge
      • Releases
      • Security Advisories
      • SymfonyInsight
      • Twig
      • SensioLabs
    • Services

      • SensioLabs services
      • Train developers
      • Manage your project quality
      • Improve your project performance
      • Host Symfony projects

      Deployed on

    Follow Symfony

    Search by Algolia