PHPackages                             contentasaurus/lightncandy - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Templating &amp; Views](/categories/templating)
4. /
5. contentasaurus/lightncandy

ActiveLibrary[Templating &amp; Views](/categories/templating)

contentasaurus/lightncandy
==========================

An extremely fast PHP implementation of handlebars ( http://handlebarsjs.com/ ) and mustache ( http://mustache.github.io/ ). This package forked from Zordius/LightnCandy.

v10.95(9y ago)03513MITPHPPHP &gt;=5.4.0

Since Feb 27Pushed 9y ago1 watchersCompare

[ Source](https://github.com/contentasaurus/lightncandy)[ Packagist](https://packagist.org/packages/contentasaurus/lightncandy)[ Docs](https://github.com/zordius/lightncandy)[ RSS](/packages/contentasaurus-lightncandy/feed)WikiDiscussions master Synced 2mo ago

READMEChangelog (1)Dependencies (1)Versions (25)Used By (3)

LightnCandy
===========

[](#lightncandy)

⚡🍭 An extremely fast PHP implementation of handlebars (  ) and mustache (  ).

Travis CI status: [![Unit testing](https://camo.githubusercontent.com/20e17fcb2f0b10c80027159cd4bed7a14a376a271007d2581900444f53b40d6d/68747470733a2f2f7472617669732d63692e6f72672f7a6f72646975732f6c696768746e63616e64792e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/zordius/lightncandy) [![Regression testing](https://camo.githubusercontent.com/6eb54e036baec6d0be234901d79e2a29038cef90df5c62012d6ff1918dd327f6/68747470733a2f2f7472617669732d63692e6f72672f7a6f72646975732f48616e646c6562617273546573742e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/zordius/HandlebarsTest)

Scrutinizer CI status: [![Code Coverage](https://camo.githubusercontent.com/5ee1c5680b3d7cb4c6752d4fe8047bd58bf76c1b9afbaf780e9883c0ac63fc94/68747470733a2f2f696d672e736869656c64732e696f2f7363727574696e697a65722f636f7665726167652f672f7a6f72646975732f6c696768746e63616e64792e737667)](https://scrutinizer-ci.com/g/zordius/lightncandy/)

Package on packagist: [![Latest Stable Version](https://camo.githubusercontent.com/867f826278b6e940ed5a8fd8c645fa11fc603718a7104592e49228e1ddc379a3/68747470733a2f2f706f7365722e707567782e6f72672f7a6f72646975732f6c696768746e63616e64792f762f737461626c652e737667)](https://packagist.org/packages/zordius/lightncandy) [![License](https://camo.githubusercontent.com/0b2a7e49e271c0cc3d404eff69c17b2572c3bd17f6d05accaf82df8375467167/68747470733a2f2f706f7365722e707567782e6f72672f7a6f72646975732f6c696768746e63616e64792f6c6963656e73652e737667)](https://github.com/zordius/lightncandy/blob/master/LICENSE.txt) [![Total Downloads](https://camo.githubusercontent.com/5954a2793b7ff105be4263c784913d17f1f841d409440218800ad92d345f0a13/68747470733a2f2f706f7365722e707567782e6f72672f7a6f72646975732f6c696768746e63616e64792f646f776e6c6f616473)](https://packagist.org/packages/zordius/lightncandy) [![HHVM Status](https://camo.githubusercontent.com/31956ab092e5c3a846b6dca78c7243a8586f3dfd6bab9c7e03736529cca42717/687474703a2f2f6868766d2e683463632e64652f62616467652f7a6f72646975732f6c696768746e63616e64792e7376673f7374796c653d666c6174)](http://hhvm.h4cc.de/package/zordius/lightncandy)

Features
--------

[](#features)

- Logicless template: mustache (  ) or handlebars (  ) .
- Compile template to **pure PHP** code. Examples:
    - [Template A](https://github.com/zordius/HandlebarsTest/blob/master/fixture/001-simple-vars.tmpl) generated [PHP A](https://github.com/zordius/HandlebarsTest/blob/master/fixture/001-simple-vars.php)
    - [Template B](https://github.com/zordius/HandlebarsTest/blob/master/fixture/016-hb-eachthis.tmpl) generated [PHP B](https://github.com/zordius/HandlebarsTest/blob/master/fixture/016-hb-eachthis.php)
- **FAST!**
    - Runs 2~7 times faster than [mustache.php](https://github.com/bobthecow/mustache.php) (Justin Hileman/bobthecow implementation).
    - Runs 2~7 times faster than [mustache-php](https://github.com/dingram/mustache-php) (Dave Ingram implementation).
    - Runs 10~50 times faster than [handlebars.php](https://github.com/XaminProject/handlebars.php).
    - Detail performance test reports can be found [here](https://github.com/zordius/HandlebarsTest), go  to see charts.
- **SMALL!** all PHP files in 147K
- **ROBUST!**
    - 100% supports [mustache spec v1.1.3](https://github.com/mustache/spec). For the optional lambda module, supports 4 of 10 specs.
    - Supports almost all [handlebars.js spec](https://github.com/jbboehr/handlebars-spec)
    - Output [SAME](https://github.com/zordius/HandlebarsTest/blob/master/FEATURES.md) with [handlebars.js](https://github.com/wycats/handlebars.js)
- **FLEXIBLE!**
    - Lot of [options](#compile-options) to change features and behaviors.
- Context generation
    - Analyze used features from your template (execute `LightnCandy::getContext()` to get it) .
- Debug
    - [Generate debug version template](#template-debugging)
        - Find out missing data when rendering template.
        - Generate visually debug template.
- Standalone Template
    - The compiled PHP code can run without any PHP library. You do not need to include LightnCandy when execute rendering function.

Installation
------------

[](#installation)

Use Composer (  ) to install LightnCandy:

```
composer require zordius/lightncandy:dev-master

```

**UPGRADE NOTICE**

- Please check [HISTORY.md](HISTORY.md) for versions history.
- Please check [UPGRADE.md](UPGRADE.md) for upgrade notice.

Documents
---------

[](#documents)

- [Quick Start](https://zordius.github.io/HandlebarsCookbook/9000-quickstart.html)

Compile Options
---------------

[](#compile-options)

You can apply more options by running `LightnCandy::compile($template, $options)`:

```
LightnCandy::compile($template, Array(
    'flags' => LightnCandy::FLAG_ERROR_LOG | LightnCandy::FLAG_STANDALONEPHP
));
```

Default is to compile the template as PHP, which can be run as fast as possible (flags = [FLAG\_BESTPERFORMANCE](https://zordius.github.io/HandlebarsCookbook/LC-FLAG_BESTPERFORMANCE.html)).

**Error Handling**

- [FLAG\_ERROR\_LOG](https://zordius.github.io/HandlebarsCookbook/LC-FLAG_ERROR_LOG.html)
- [FLAG\_ERROR\_EXCEPTION](https://zordius.github.io/HandlebarsCookbook/LC-FLAG_ERROR_EXCEPTION.html)
- [FLAG\_ERROR\_SKIPPARTIAL](https://zordius.github.io/HandlebarsCookbook/LC-FLAG_ERROR_SKIPPARTIAL.html)
- `FLAG_RENDER_DEBUG` : generate debug template to show error when rendering. With this flag, the performance of rendering may be slowed.

**JavaScript Compatibility**

- [FLAG\_JSTRUE](https://zordius.github.io/HandlebarsCookbook/LC-FLAG_JSTRUE.html)
- [FLAG\_JSOBJECT](https://zordius.github.io/HandlebarsCookbook/LC-FLAG_JSOBJECT.html)
- [FLAG\_JSLENGTH](https://zordius.github.io/HandlebarsCookbook/LC-FLAG_JSLENGTH.html)
- [FLAG\_JS](https://zordius.github.io/HandlebarsCookbook/LC-FLAG_JS.html)

**Mustache Compatibility**

- `FLAG_MUSTACHELOOKUP` : align recursive lookup up behaviors with mustache specification. And, the rendering performance will be worse.
- `FLAG_MUSTACHELAMBDA` : support simple lambda logic as mustache specification. And, the rendering performance will be worse.
- `FLAG_NOHBHELPERS` : Do not compile handlebars.js builtin helpers. With this option, `{{#with}}`, `{{#if}}`, `{{#unless}}`, `{{#each}}` means normal section, and `{{#with foo}}`, `{{#if foo}}`, `{{#unless foo}}`, `{{#each foo}}` will cause compile error.
- `FLAG_MUSTACHE` : support all mustache specification but performance drop, same with `FLAG_ERROR_SKIPPARTIAL` + `FLAG_MUSTACHELOOKUP` + `FLAG_MUSTACHELAMBDA` + `FLAG_NOHBHELPERS` + `FLAG_RUNTIMEPARTIAL` + `FLAG_JS`.

**Handlebars Compatibility**

- [FLAG\_THIS](https://zordius.github.io/HandlebarsCookbook/LC-FLAG_THIS.html)
- [FLAG\_PARENT](https://zordius.github.io/HandlebarsCookbook/LC-FLAG_PARENT.html)
- [FLAG\_HBESCAPE](https://zordius.github.io/HandlebarsCookbook/LC-FLAG_HBESCAPE.html)
- [FLAG\_ADVARNAME](https://zordius.github.io/HandlebarsCookbook/LC-FLAG_ADVARNAME.html)
- [FLAG\_NAMEDARG](https://zordius.github.io/HandlebarsCookbook/LC-FLAG_NAMEDARG.html)
- [FLAG\_SLASH](https://zordius.github.io/HandlebarsCookbook/LC-FLAG_SLASH.html)
- [FLAG\_ELSE](https://zordius.github.io/HandlebarsCookbook/LC-FLAG_ELSE.html)
- `FLAG_RAWBLOCK`: support `{{{{raw_block}}}}any_char_or_{{foo}}_as_raw_string{{{{/raw_block}}}}`.
- `FLAG_SPACECTL` : support space control `{{~ }}` or `{{ ~}}` in template. Otherwise, `{{~ }}` or `{{ ~}}` will cause template error.
- `FLAG_HANDLEBARSLAMBDA` : support lambda logic as handlebars.js specification. And, the rendering performance will be worse.
- `FLAG_SPVARS` : support special variables include @root, @index, @key, @first, @last. Otherwise, compile these variable names with default parsing logic.
- `FLAG_HANDLEBARS` : support most handlebars extensions and also keep performance good, same with `FLAG_THIS` + `FLAG_PARENT` + `FLAG_HBESCAPE` + `FLAG_ADVARNAME` + `FLAG_SPACECTL` + `FLAG_NAMEDARG` + `FLAG_SPVARS` + `FLAG_SLASH` + `FLAG_ELSE` + `FLAG_RAWBLOCK`.
- `FLAG_HANDLEBARSJS` : support most handlebars.js + javascript behaviors and also keep performance good, same with `FLAG_JS` + `FLAG_HANDLEBARS`.
- `FLAG_HANDLEBARSJS_FULL` : enable all supported handlebars.js behaviors but performance drop, same with `FLAG_HANDLEBARSJS` + `FLAG_INSTANCE` + `FLAG_RUNTIMEPARTIAL` + `FLAG_MUSTACHELOOKUP` + `FLAG_HANDLEBARSLAMBDA`.

**Handlebars Options**

- [FLAG\_NOESCAPE](https://zordius.github.io/HandlebarsCookbook/LC-FLAG_NOESCAPE.html)
- [FLAG\_PARTIALNEWCONTEXT](https://zordius.github.io/HandlebarsCookbook/LC-FLAG_PARTIALNEWCONTEXT.html)
- `FLAG_IGNORESTANDALONE` : prevent standalone detection on `{{#foo}}`, `{{/foo}}` or `{{^}}`, the behavior is same with handlebars.js ignoreStandalone compile time option.
- `FLAG_STRINGPARAMS` : pass variable name as string to helpers, the behavior is same with handlebars.js stringParams compile time option.
- `FLAG_KNOWNHELPERSONLY`: Only pass current context to lambda, the behavior is same with handlebars.js knownHelpersOnly compile time option.
- `FLAG_PREVENTINDENT` : align partial indent behavior with mustache specification. This is same with handlebars.js preventIndent copmile time option.

**PHP**

- [FLAG\_STANDALONEPHP](https://zordius.github.io/HandlebarsCookbook/LC-FLAG_STANDALONEPHP.html)
- [FLAG\_EXTHELPER](https://zordius.github.io/HandlebarsCookbook/LC-FLAG_EXTHELPER.html)
- [FLAG\_RUNTIMEPARTIAL](https://zordius.github.io/HandlebarsCookbook/LC-FLAG_RUNTIMEPARTIAL.html)
- [FLAG\_PROPERTY](https://zordius.github.io/HandlebarsCookbook/LC-FLAG_PROPERTY.html)
- [FLAG\_METHOD](https://zordius.github.io/HandlebarsCookbook/LC-FLAG_METHOD.html)
- [FLAG\_INSTANCE](https://zordius.github.io/HandlebarsCookbook/LC-FLAG_INSTANCE.html)
- [FLAG\_ECHO](https://zordius.github.io/HandlebarsCookbook/LC-FLAG_ECHO.html)
- [FLAG\_BESTPERFORMANCE](https://zordius.github.io/HandlebarsCookbook/LC-FLAG_BESTPERFORMANCE.html)

Partial Support
---------------

[](#partial-support)

- [Example of compile time partial](https://zordius.github.io/HandlebarsCookbook/0011-partial.html)
- [Example of partial context changing](https://zordius.github.io/HandlebarsCookbook/0024-partialcontext.html)
- [use dynamic partial](https://zordius.github.io/HandlebarsCookbook/0028-dynamicpartial.html)
- [The partialresolver option](https://zordius.github.io/HandlebarsCookbook/9902-lcop-partialresolver.html)

Custom Helper
-------------

[](#custom-helper)

- [Custom Helpers in LighnCandy](https://zordius.github.io/HandlebarsCookbook/9001-customhelper.html)
- [The $options Object](https://zordius.github.io/HandlebarsCookbook/9002-helperoptions.html)
- [Use SafeString](https://zordius.github.io/HandlebarsCookbook/9003-helperescaping.html)
- [The helperresolver option](https://zordius.github.io/HandlebarsCookbook/9901-lcop-helperresolver.html)

Custom Helper Examples
----------------------

[](#custom-helper-examples)

**\#mywith (context change)**

- LightnCandy

```
// LightnCandy sample, #mywith works same with #with
$php = LightnCandy::compile($template, Array(
    'flags' => LightnCandy::FLAG_HANDLEBARSJS,
    'helpers' => Array(
        'mywith' => function ($context, $options) {
            return $options['fn']($context);
        }
    )
));
```

- Handlebars.js

```
// Handlebars.js sample, #mywith works same with #with
Handlebars.registerHelper('mywith', function(context, options) {
    return options.fn(context);
});
```

**\#myeach (context change)**

- LightnCandy

```
// LightnCandy sample, #myeach works same with #each
$php = LightnCandy::compile($template, Array(
    'flags' => LightnCandy::FLAG_HANDLEBARSJS,
    'helpers' => Array(
        'myeach' => function ($context, $options) {
            $ret = '';
            foreach ($context as $cx) {
                $ret .= $options['fn']($cx);
            }
            return $ret;
        }
    )
));
```

- Handlebars.js

```
// Handlebars.js sample, #myeach works same with #each
Handlebars.registerHelper('myeach', function(context, options) {
    var ret = '', i, j = context.length;
    for (i = 0; i  LightnCandy::FLAG_HANDLEBARSJS,
    'helpers' => Array(
        'myif' => function ($conditional, $options) {
            if ($conditional) {
                return $options['fn']();
            } else {
                return $options['inverse']();
            }
        }
    )
));
```

- Handlebars.js

```
// Handlebars.js sample, #myif works same with #if
Handlebars.registerHelper('myif', function(conditional, options) {
    if (conditional) {
        return options.fn(this);
    } else {
        return options.inverse(this);
    }
});
```

You can use `isset($options['fn'])` to detect your custom helper is a block or not; you can also use `isset($options['inverse'])` to detect the existence of `{{else}}`.

**Data variables and context**

You can get special data variables from `$options['data']`. Using `$options['_this']` to receive current context.

```
$php = LightnCandy::compile($template, Array(
    'flags' => LightnCandy::FLAG_HANDLEBARSJS,
    'helpers' => Array(
        'getRoot' => function ($options) {
            print_r($options['_this']); // dump current context
            return $options['data']['root']; // same as {{@root}}
        }
    )
));
```

- Handlebars.js

```
Handlebars.registerHelper('getRoot', function(options) {
    console.log(this); // dump current context
    return options.data.root; // same as {{@root}}
});
```

**Private variables**

You can inject private variables into inner block when you execute child block with second parameter. The example code showed similar behavior with `{{#each}}` which sets index for child block and can be accessed with `{{@index}}`.

- LightnCandy

```
$php = LightnCandy::compile($template, Array(
    'flags' => LightnCandy::FLAG_HANDLEBARSJS,
    'helpers' => Array(
        'list' => function ($context, $options) {
            $out = '';
            $data = $options['data'];

            foreach ($context as $idx => $cx) {
                $data['index'] = $idx;
                $out .= $options['fn']($cx, Array('data' => $data));
            }

            return $out;
        }
    )
));
```

- Handlebars.js

```
Handlebars.registerHelper('list', function(context, options) {
  var out = '';
  var data = options.data ? Handlebars.createFrame(options.data) : undefined;

  for (var i=0; i array('')
));
```

Template Debugging
------------------

[](#template-debugging)

When template error happened, LightnCandy::compile() will return false. You may compile with `FLAG_ERROR_LOG` to see more error message, or compile with `FLAG_ERROR_EXCEPTION` to catch the exception.

You may generate debug version of templates with `FLAG_RENDER_DEBUG` when compile() . The debug template contained more debug information and slower (TBD: performance result) , you may pass extra LightnCandy\\Runtime options into render function to know more rendering error (missing data). For example:

```
$template = "Hello! {{name}} is {{gender}}.
Test1: {{@root.name}}
Test2: {{@root.gender}}
Test3: {{../test3}}
Test4: {{../../test4}}
Test5: {{../../.}}
Test6: {{../../[test'6]}}
{{#each .}}
each Value: {{.}}
{{/each}}
{{#.}}
section Value: {{.}}
{{/.}}
{{#if .}}IF OK!{{/if}}
{{#unless .}}Unless not OK!{{/unless}}
";

// compile to debug version
$php = LightnCandy::compile($template, Array(
    'flags' => LightnCandy::FLAG_RENDER_DEBUG | LightnCandy::FLAG_HANDLEBARSJS
));

// Get the render function
$renderer = LightnCandy::prepare($php);

// error_log() when missing data:
//   LightnCandy\Runtime: [gender] is not exist
//   LightnCandy\Runtime: ../[test] is not exist
$renderer(Array('name' => 'John'), array('debug' => LightnCandy\Runtime::DEBUG_ERROR_LOG));

// Output visual debug template with ANSI color:
echo $renderer(Array('name' => 'John'), array('debug' => LightnCandy\Runtime::DEBUG_TAGS_ANSI));

// Output debug template with HTML comments:
echo $renderer(Array('name' => 'John'), array('debug' => LightnCandy\Runtime::DEBUG_TAGS_HTML));
```

The ANSI output will be:

[![](https://github.com/zordius/lightncandy/raw/master/example_debug.png)](tests/example_debug.php)

Here are the list of LightnCandy\\Runtime debug options for render function:

- `DEBUG_ERROR_LOG` : error\_log() when missing required data
- `DEBUG_ERROR_EXCEPTION` : throw exception when missing required data
- `DEBUG_TAGS` : turn the return value of render function into normalized mustache tags
- `DEBUG_TAGS_ANSI` : turn the return value of render function into normalized mustache tags with ANSI color
- `DEBUG_TAGS_HTML` : turn the return value of render function into normalized mustache tags with HTML comments

Preprocess Partials
-------------------

[](#preprocess-partials)

If you want to do extra process before the partial be compiled, you may use `prepartial` when `compile()`. For example, this sample adds HTML comments to identify the partial by the name:

```
$php = LightnCandy::compile($template, Array(
    'flags' => LightnCandy::FLAG_HANDLEBARSJS,
    'prepartial' => function ($context, $template, $name) {
        return "$template";
    }
));
```

You may also extend [LightnCandy\\Partial](https://zordius.github.io/lightncandy/class-LightnCandy.Partial.html) by override the [prePartial()](https://zordius.github.io/lightncandy/class-LightnCandy.Partial.html#_prePartial) static method to turn your preprocess into a built-in feature.

Customize Render Function
-------------------------

[](#customize-render-function)

If you want to do extra tasks inside render function or add more comment, you may use `renderex` when `compile()` . For example, this sample embed the compile time comment into the template:

```
$php = LightnCandy::compile($template, Array(
    'flags' => LightnCandy::FLAG_HANDLEBARSJS,
    'renderex' => '// Compiled at ' . date('Y-m-d h:i:s')
));
```

Your render function will be:

```
function ($in) {
    $cx = array(...);
    // compiled at 1999-12-31 00:00:00
    return .....
}
```

Please make sure the passed in `renderex` is valid PHP, LightnCandy will not check it.

Customize Rendering Runtime Class
---------------------------------

[](#customize-rendering-runtime-class)

If you want to extend `LightnCandy\Runtime` class and replace the default runtime library, you may use `runtime` when `compile()` . For example, this sample will generate render function based on your extended `MyRunTime`:

```
// Customized runtime library to debug {{{foo}}}
class MyRunTime extends LightnCandy\Runtime {
    public static function raw($cx, $v) {
        return '[[DEBUG:raw()=>' . var_export($v, true) . ']]';
    }
}

// Use MyRunTime as runtime library
$php = LightnCandy::compile($template, Array(
    'flags' => LightnCandy::FLAG_HANDLEBARSJS,
    'runtime' => 'MyRunTime'
));
```

Please make sure `MyRunTime` exists when compile() or rendering based on your `FLAG_STANDALONEPHP` .

Unsupported Feature
-------------------

[](#unsupported-feature)

- `{{foo/bar}}` style variable name, it is deprecated in official handlebars.js document, please use this style: `{{foo.bar}}`.

Suggested Handlebars Template Practices
---------------------------------------

[](#suggested-handlebars-template-practices)

- Prevent to use `{{#with}}` . I think `{{path.to.val}}` is more readable then `{{#with path.to}}{{val}}{{/with}}`; when using `{{#with}}` you will confusing on scope changing. `{{#with}}` only save you very little time when you access many variables under same path, but cost you a lot time when you need to understand then maintain a template.
- use `{{{val}}}` when you do not require HTML escaped output on the value. It is better performance, too.
- If you wanna display `{{`, use this: `{{#with "{{"}}{{.}}{{/with}}`.
- Prevent to use custom helper if you want to reuse your template in different language. Or, you may need to implement different versions of helper in different languages.
- For best performance, you should only use 'compile on demand' pattern when you are in development stage. Before you go to production, you can `LightnCandy::compile()` on all your templates, save all generated PHP codes, and deploy these generated files (You may need to maintain a build process for this) . **DO NOT COMPILE ON PRODUCTION** , it also a best practice for security. Adding cache for 'compile on demand' is not the best solution. If you want to build some library or framework based on LightnCandy, think about this scenario.
- Recompile your templates when you upgrade LightnCandy every time.

Detail Feature list
-------------------

[](#detail-feature-list)

Go  to see more feature description about handlebars.js. All features align with it.

- Exact same CR/LF behavior with handlebars.js
- Exact same CR/LF bahavior with mustache spec
- Exact same 'true' or 'false' output with handlebars.js (require `FLAG_JSTRUE`)
- Exact same '\[object Object\]' output or join(',' array) output with handlebars.js (require `FLAG_JSOBJECT`)
- Can place heading/tailing space, tab, CR/LF inside `{{ var }}` or `{{{ var }}}`
- Indent behavior of the partial same with mustache spec
- Recursive variable lookup to parent context behavior same with mustache spec (require `FLAG_MUSTACHELOOKUP`)
- `{{{value}}}` or `{{&value}}` : raw variable
    - true as 'true' (require `FLAG_JSTRUE`)
    - false as 'false' (require `FLAG_TRUE`)
- `{{value}}` : HTML escaped variable
    - true as 'true' (require `FLAG_JSTRUE`)
    - false as 'false' (require `FLAG_JSTRUE`)
- `{{{path.to.value}}}` : dot notation, raw
- `{{path.to.value}}` : dot notation, HTML escaped
- `{{.}}` : current context, HTML escaped
- `{{{.}}}` : current context, raw
- `{{this}}` : current context, HTML escaped (require `FLAG_THIS`)
- `{{{this}}}` : current context, raw (require `FLAG_THIS`)
- `{{#value}}` : section
    - false, undefined and null will skip the section
    - true will run the section with original scope
    - All others will run the section with new scope (includes 0, 1, -1, '', '1', '0', '-1', 'false', Array, ...)
- `{{/value}}` : end section
- `{{^value}}` : inverted section
    - false, undefined and null will run the section with original scope
    - All others will skip the section (includes 0, 1, -1, '', '1', '0', '-1', 'false', Array, ...)
- `{{! comment}}` : comment
- `{{!-- comment or {{ or }} --}}` : extended comment that can contain }} or {{ .
- `{{==}}` : set delimiter to custom string , the custom string can not contain `=` . Check  for more example.
- `{{#each var}}` : each loop
- `{{#each}}` : each loop on {{.}}
- `{{/each}}` : end loop
- `{{#if var}}` : run if logic with original scope (null, false, empty Array and '' will skip this block)
- `{{#if foo includeZero=true}}` : result as true when foo === 0 (require `FLAG_NAMEDARG`)
- `{{/if}}` : end if
- `{{else}}` or `{{^}}` : run else logic, should between `{{#if var}}` and `{{/if}}` ; or between `{{#unless var}}` and `{{/unless}}`; or between `{{#foo}}` and `{{/foo}}`; or between `{{#each var}}` and `{{/each}}`; or between `{{#with var}}` and `{{/with}}`. (require `FLAG_ELSE`)
- `{{#if foo}} ... {{else if bar}} ... {{/if}}` : chained if else blocks
- `{{#unless var}}` : run unless logic with original scope (null, false, empty Array and '' will render this block)
- `{{#unless foo}} ... {{else if bar}} ... {{/unless}}` : chained unless else blocks
- `{{#unless foo}} ... {{else unless bar}} ... {{/unless}}` : chained unless else blocks
- `{{#foo}} ... {{else bar}} ... {{/foo}}` : custom helper chained else blocks
- `{{#with var}}` : change context scope. If the var is false or an empty array, skip included section.
- `{{#with bar as |foo|}}` : change context to bar and set the value as foo. (require `FLAG_ADVARNAME`)
- `{{lookup foo bar}}` : lookup foo by value of bar as key.
- `{{../var}}` : parent template scope. (require `FLAG_PARENT`)
- `{{>file}}` : partial; include another template inside a template.
- `{{>file foo}}` : partial with new context (require `FLAG_RUNTIMEPARTIAL`)
- `{{>file foo bar=another}}` : partial with new context which mixed with followed key value (require `FLAG_RUNTIMEPARTIAL`)
- `{{>(helper) foo}}` : include dynamic partial by name provided from a helper (require `FLAG_RUNTIMEPARTIAL`)
- `{{@index}}` : references to current index in a `{{#each}}` loop on an array. (require `FLAG_SPVARS`)
- `{{@key}}` : references to current key in a `{{#each}}` loop on an object. (require `FLAG_SPVARS`)
- `{{@root}}` : references to root context. (require `FLAG_SPVARS`)
- `{{@first}}` : true when looping at first item. (require `FLAG_SPVARS`)
- `{{@last}}` : true when looping at last item. (require `FLAG_SPVARS`)
- `{{@root.path.to.value}}` : references to root context then follow the path. (require `FLAG_SPVARS`)
- `{{@../index}}` : access to parent loop index. (require `FLAG_SPVARS` and `FLAG_PARENT`)
- `{{@../key}}` : access to parent loop key. (require `FLAG_SPVARS` and `FLAG_PARENT`)
- `{{foo.[ba.r].[#spec].0.ok}}` : references to $CurrentConext\['foo'\]\['ba.r'\]\['#spec'\]\[0\]\['ok'\] . (require `FLAG_ADVARNAME`)
- `{{~any_valid_tag}}` : Space control, remove all previous spacing (includes CR/LF, tab, space; stop on any none spacing character) (require `FLAG_SPACECTL`)
- `{{any_valid_tag~}}` : Space control, remove all next spacing (includes CR/LF, tab, space; stop on any none spacing character) (require `FLAG_SPACECTL`)
- `{{{helper var}}}` : Execute custom helper then render the result
- `{{helper var}}` : Execute custom helper then render the HTML escaped result
- `{{helper "str"}}` or `{{helper 'str'}}` : Execute custom helper with string arguments (require `FLAG_ADVARNAME`)
- `{{helper 123 null true false undefined}}` : Pass number, true, false, null or undefined into helper
- `{{helper name1=var name2=var2}}` : Execute custom helper with named arguments (require `FLAG_NAMEDARG`)
- `{{#helper ...}}...{{/helper}}` : Execute block custom helper
- `{{helper (helper2 foo) bar}}` : Execute custom helpers as subexpression (require `FLAG_ADVARNAME`)
- `{{{{raw_block}}}} {{will_not_parsed}} {{{{/raw_block}}}}` : Raw block (require `FLAG_RAWBLOCK`)
- `{{#> foo}}block{{/foo}}` : Partial block, provide `foo` partial default content (require `FLAG_RUNTIMEPARTIAL`)
- `{{#> @partial-block}}` : access partial block content inside a partial
- `{{#*inline "partial_name"}}...{{/inline}}` : Inline partial, provide a partial and overwrite the original one.
- `{{log foo}}` : output value to stderr for debug.

Framework Integration
---------------------

[](#framework-integration)

- [Slim 3.0.x](https://github.com/endel/slim-lightncandy-view)
- [Laravel 4](https://github.com/samwalshnz/lightncandy-l4)
- [Laravel 5](https://github.com/ProAI/laravel-handlebars)
- [yii2](https://github.com/kfreiman/yii2-lightncandy)
- [Symfony3](https://packagist.org/packages/jays-de/handlebars-bundle)

Tools
-----

[](#tools)

- CLI:

###  Health Score

32

—

LowBetter than 72% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity12

Limited adoption so far

Community22

Small or concentrated contributor base

Maturity68

Established project with proven stability

 Bus Factor4

4 contributors hold 50%+ of commits

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~43 days

Recently: every ~53 days

Total

23

Last Release

3498d ago

Major Versions

v0.95 → v10.952016-10-15

PHP version history (2 changes)v0.9PHP &gt;=5.3.0

v0.90PHP &gt;=5.4.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/846a6e41443f6f29229485706ac0fae1d82d87a1751c88d8a150e57e7047a725?d=identicon)[contentasaurus](/maintainers/contentasaurus)

---

Top Contributors

[![ebernhardson](https://avatars.githubusercontent.com/u/558434?v=4)](https://github.com/ebernhardson "ebernhardson (4 commits)")[![ssnau](https://avatars.githubusercontent.com/u/738660?v=4)](https://github.com/ssnau "ssnau (4 commits)")[![endel](https://avatars.githubusercontent.com/u/130494?v=4)](https://github.com/endel "endel (3 commits)")[![joshington25](https://avatars.githubusercontent.com/u/185387369?v=4)](https://github.com/joshington25 "joshington25 (3 commits)")[![shahyar](https://avatars.githubusercontent.com/u/255846?v=4)](https://github.com/shahyar "shahyar (2 commits)")[![brunobg](https://avatars.githubusercontent.com/u/798800?v=4)](https://github.com/brunobg "brunobg (2 commits)")[![matthiasmullie](https://avatars.githubusercontent.com/u/312776?v=4)](https://github.com/matthiasmullie "matthiasmullie (1 commits)")[![puritys](https://avatars.githubusercontent.com/u/1295178?v=4)](https://github.com/puritys "puritys (1 commits)")[![Southparkfan](https://avatars.githubusercontent.com/u/5605877?v=4)](https://github.com/Southparkfan "Southparkfan (1 commits)")[![thesjg](https://avatars.githubusercontent.com/u/6374?v=4)](https://github.com/thesjg "thesjg (1 commits)")[![flashvnn](https://avatars.githubusercontent.com/u/1784547?v=4)](https://github.com/flashvnn "flashvnn (1 commits)")[![jmgq](https://avatars.githubusercontent.com/u/7648952?v=4)](https://github.com/jmgq "jmgq (1 commits)")[![keeto](https://avatars.githubusercontent.com/u/19396?v=4)](https://github.com/keeto "keeto (1 commits)")[![kfreiman](https://avatars.githubusercontent.com/u/2056294?v=4)](https://github.com/kfreiman "kfreiman (1 commits)")[![legoktm](https://avatars.githubusercontent.com/u/81392?v=4)](https://github.com/legoktm "legoktm (1 commits)")

---

Tags

phptemplatemustachehandlebarslogicless

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/contentasaurus-lightncandy/health.svg)

```
[![Health](https://phpackages.com/badges/contentasaurus-lightncandy/health.svg)](https://phpackages.com/packages/contentasaurus-lightncandy)
```

###  Alternatives

[zordius/lightncandy

An extremely fast PHP implementation of handlebars ( http://handlebarsjs.com/ ) and mustache ( http://mustache.github.io/ ).

60910.5M45](/packages/zordius-lightncandy)[wrklst/docxmustache

docx template manipulation class, based on mustache templating language

578.1k](/packages/wrklst-docxmustache)[devtheorem/php-handlebars

A blazing fast, spec-compliant PHP implementation of Handlebars.

1924.8k2](/packages/devtheorem-php-handlebars)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
