百科.dev
全部条目在线工具AI 编程趋势榜开源项目技术资讯提交条目
登录
< 返回工具列表
L

lightncandy

> 编程语言
开源

一个极其快速的 PHP 实现的 handlebars (http://handlebarsjs.com/) 和 mustache (http://mustache.GitHub.io/),

610 stars0 点赞1 次浏览
访问官网GitHub

工具介绍

一个极其快速的 PHP 实现的 handlebars (http://handlebarsjs.com/) 和 mustache (http://mustache.GitHub.io/),

LightnCandy

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

CI status: tested PHP: 7.1, 7.2, 7.3, 7.4, 8.0, 8.1

Package on packagist:

Features

  • Logicless template: mustache ( http://mustache.github.com/ ) or handlebars ( http://handlebarsjs.com/ ) .
  • Compile template to pure PHP code. Examples:
    • Template A generated PHP A
    • Template B generated PHP B
  • FAST!
    • Runs 2~7 times faster than mustache.php (Justin Hileman/bobthecow implementation).
    • Runs 2~7 times faster than mustache-php (Dave Ingram implementation).
    • Runs 10~50 times faster than handlebars.php.
    • Detail performance test reports can be found here, go http://zordius.github.io/HandlebarsTest/ to see charts.
  • SMALL! all PHP files in 189K
  • ROBUST!
    • 100% supports mustache spec v1.1.3. For the optional lambda module, supports 4 of 10 specs.
    • Supports almost all handlebars.js spec
    • Output SAME with handlebars.js
  • FLEXIBLE!
    • Lot of 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
      • 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

Use Composer ( https://getcomposer.org/ ) to install LightnCandy:

composer require zordius/lightncandy:dev-master

UPGRADE NOTICE

  • Please check HISTORY.md for versions history.
  • Please check UPGRADE.md for upgrade notice.

Documents

  • Quick Start

Compile Options

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

php
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).

Error Handling

  • FLAG_ERROR_LOG
  • FLAG_ERROR_EXCEPTION
  • FLAG_ERROR_SKIPPARTIAL
  • FLAG_RENDER_DEBUG

JavaScript Compatibility

  • FLAG_JSTRUE
  • FLAG_JSOBJECT
  • FLAG_JSLENGTH
  • FLAG_JS

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_MUSTACHESECTION : align section context behaviors with mustache.js.
  • FLAG_MUSTACHE : support all mustache specification but performance drop, same with FLAG_ERROR_SKIPPARTIAL + FLAG_MUSTACHELOOKUP + FLAG_MUSTACHELAMBDA + FLAG_NOHBHELPERS + FLAG_RUNTIMEPARTIAL + FLAG_JSTRUE + FLAG_JSOBJECT.

Handlebars Compatibility

  • FLAG_THIS
  • FLAG_PARENT
  • FLAG_HBESCAPE
  • FLAG_ADVARNAME
  • FLAG_NAMEDARG
  • FLAG_SLASH
  • FLAG_ELSE
  • FLAG_RAWBLOCK: support {{{{raw_block}}}}any_char_or_{{foo}}_as_raw_string{{{{/raw_block}}}}.
  • 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_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
  • FLAG_PARTIALNEWCONTEXT
  • 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
  • FLAG_EXTHELPER
  • FLAG_RUNTIMEPARTIAL
  • FLAG_PROPERTY
  • FLAG_METHOD
  • FLAG_INSTANCE
  • FLAG_ECHO
  • FLAG_BESTPERFORMANCE

Partial Support

  • Example of compile time partial
  • Example of partial context changing
  • use dynamic partial
  • The partialresolver option

Custom Helper

  • Custom Helpers in LighnCandy
  • The $options Object
  • Use SafeString
  • The helperresolver option

Custom Helper Examples

#mywith (context change)

  • LightnCandy
php
// 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
javascript
// Handlebars.js sample, #mywith works same with #with
Handlebars.registerHelper('mywith', function(context, options) {
    return options.fn(context);
});

#myeach (context change)

  • LightnCandy
php
// 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
javascript
// 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
javascript
// 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
$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
javascript
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
$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
javascript
Handlebars.registerHelper('list', function(context, options) {
  var out = '';
  var data = options.data ? Handlebars.createFrame(options.data) : undefined;

  for (var i=0; i=}}` to change delimiters to `` , but the change will not affect included partials.

If you want to change default delimiters for a template and all included partials, you may `compile()` it with `delimiters` option:

```php
LightnCandy::compile('I wanna use  as delimiters!', array(
    'delimiters' => array('')
));

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:

php
$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
$phpStr = LightnCandy::compile($template, array(
    'flags' => LightnCandy::FLAG_RENDER_DEBUG | LightnCandy::FLAG_HANDLEBARSJS
));

// Save the compiled PHP code into a php file
file_put_contents('render.php', '');

// Get the render function from the php file
$renderer = include('render.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));

…

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

You may also extend LightnCandy\Partial by override the prePartial() static method to turn your preprocess into a built-in feature.

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 compil

Issues· 0 开放

查看全部 Issues在 GitHub 打开

暂无开放 Issues,或尚未同步最近议题。

> 标签

PHPhandlebarshandlebars-jslightncandymustache

暂无评论,来聊聊你的看法吧

> 工具信息

发布日期2026年8月1日
最后更新2026年9月17日
分类编程语言
定价开源

> 相关工具

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言