Added
compatcompile option to enable recursive field lookup. When set totrue, if a template variable is not found in the current scope it will automatically be looked up in parent scopes, matching Mustache's behavior.- Official Mustache spec tests are now run to verify
compatfunctionality. partialResolverruntime option: aClosure(string $name): ?Closurecalled lazily the first time each unresolved partial is called. This replaces the previous compile-timepartialResolveroption.
Changed
- Improved compiler performance and reduced memory usage by simplifying internal state.
- Optimized rendering of indented partials.
Removed
-
partialsandpartialResolvercompile-time options. These options baked partials into the generated PHP closure, causing each partial to be recompiled and duplicated across every template that referenced it. Partials should now be supplied when invoking a template via thepartialsorpartialResolverruntime options.Upgrade: if you were passing partials via
Options, move them to the runtime options instead:// Before $template = Handlebars::compile($source, new Options( partials: ['footer' => '<footer>...</footer>'], partialResolver: fn($name) => loadTemplate($name), )); echo $template($data); // After $template = Handlebars::compile($source); echo $template($data, [ 'partials' => ['footer' => Handlebars::compile('<footer>...</footer>')], 'partialResolver' => fn($name) => Handlebars::compile(loadTemplate($name)), ]);
This change makes it possible to precompile all partials in a directory, and then lazily import them on first use for optimal performance. See the example in the readme.
Fixed
- Failure to invoke
@datavariables containing a closure when passed toiforunlesshelpers. - Hoisted block closures leaked into the caller's scope when a precompiled template was loaded via
include/require. - Hash arguments passed to a partial were ignored when the partial was invoked in certain non-array contexts.
- Block helpers returning a nested or non-list array were not stringified correctly.
- Partials with literal names (
{{> true}},{{> false}},{{> null}},{{> undefined}}) were not resolved correctly: boolean names caused a type error, andnull/undefinedsilently rendered nothing.