Skip to content

Commit af4fa67

Browse files
committed
Import Closure for better code readability
Also improved some docblock comments.
1 parent 59caa32 commit af4fa67

3 files changed

Lines changed: 51 additions & 51 deletions

File tree

src/Handlebars.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,20 @@
22

33
namespace DevTheorem\Handlebars;
44

5+
use Closure;
56
use DevTheorem\HandlebarsParser\ParserFactory;
67

78
/**
8-
* @phpstan-type RenderOptions array{data?: array<mixed>, helpers?: array<string, \Closure>, partials?: array<string, \Closure>}
9-
* @phpstan-type Template \Closure(mixed=, RenderOptions=): string
9+
* @phpstan-type RenderOptions array{data?: array<mixed>, helpers?: array<string, Closure>, partials?: array<string, Closure>}
10+
* @phpstan-type Template Closure(mixed=, RenderOptions=): string
1011
*/
1112
final class Handlebars
1213
{
1314
/**
1415
* Compiles a template so it can be executed immediately.
1516
* @return Template
1617
*/
17-
public static function compile(string $template, Options $options = new Options()): \Closure
18+
public static function compile(string $template, Options $options = new Options()): Closure
1819
{
1920
return self::template(self::precompile($template, $options));
2021
}
@@ -39,7 +40,7 @@ public static function precompile(string $template, Options $options = new Optio
3940
* Sets up a template that was precompiled with precompile().
4041
* @return Template
4142
*/
42-
public static function template(string $templateSpec): \Closure
43+
public static function template(string $templateSpec): Closure
4344
{
4445
return eval($templateSpec);
4546
}

src/Runtime.php

Lines changed: 40 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@
44

55
namespace DevTheorem\Handlebars;
66

7+
use Closure;
8+
79
/**
810
* @internal
911
* @phpstan-import-type RenderOptions from Handlebars
1012
*/
1113
final class Runtime
1214
{
13-
/** @var array<string, \Closure>|null */
15+
/** @var array<string, Closure>|null */
1416
private static ?array $defaultHelpers = null;
1517
/** Parent RuntimeContext during a user-partial invocation, null at top level. */
1618
private static ?RuntimeContext $partialContext = null;
@@ -19,7 +21,7 @@ final class Runtime
1921
* Default implementations of the built-in Handlebars helpers.
2022
* These are pre-registered in every runtime context and can be overridden.
2123
*
22-
* @return array<string, \Closure>
24+
* @return array<string, Closure>
2325
*/
2426
public static function defaultHelpers(): array
2527
{
@@ -30,7 +32,7 @@ public static function defaultHelpers(): array
3032
}
3133
/** @var HelperOptions $options */
3234
$options = $args[1];
33-
$condition = $args[0] instanceof \Closure ? $args[0]($options->scope) : $args[0];
35+
$condition = $args[0] instanceof Closure ? $args[0]($options->scope) : $args[0];
3436
return static::ifvar($condition, (bool) ($options->hash['includeZero'] ?? false))
3537
? $options->fn($options->scope)
3638
: $options->inverse();
@@ -41,7 +43,7 @@ public static function defaultHelpers(): array
4143
}
4244
/** @var HelperOptions $options */
4345
$options = $args[1];
44-
$condition = $args[0] instanceof \Closure ? $args[0]($options->scope) : $args[0];
46+
$condition = $args[0] instanceof Closure ? $args[0]($options->scope) : $args[0];
4547
return static::ifvar($condition, (bool) ($options->hash['includeZero'] ?? false))
4648
? $options->inverse()
4749
: $options->fn($options->scope);
@@ -50,7 +52,7 @@ public static function defaultHelpers(): array
5052
if (!$options) {
5153
throw new \Exception('Must pass iterator to #each');
5254
}
53-
if ($context instanceof \Closure) {
55+
if ($context instanceof Closure) {
5456
$context = $context($options->scope);
5557
}
5658
if ($context instanceof \Traversable) {
@@ -66,7 +68,7 @@ public static function defaultHelpers(): array
6668
}
6769
/** @var HelperOptions $options */
6870
$options = $args[1];
69-
$context = $args[0] instanceof \Closure ? $args[0]($options->scope) : $args[0];
71+
$context = $args[0] instanceof Closure ? $args[0]($options->scope) : $args[0];
7072
if (static::ifvar($context)) {
7173
return $options->fn($context, ['blockParams' => [$context]]);
7274
}
@@ -164,7 +166,7 @@ public static function lookupLength(mixed $base, bool $strict = false): mixed
164166
* Build a RuntimeContext from raw render options and compile-time partial closures.
165167
*
166168
* @param RenderOptions $options
167-
* @param array<string, \Closure> $compiledPartials
169+
* @param array<string, Closure> $compiledPartials
168170
*/
169171
public static function createContext(mixed $context, array $options, array $compiledPartials): RuntimeContext
170172
{
@@ -201,11 +203,12 @@ public static function createContext(mixed $context, array $options, array $comp
201203

202204
/**
203205
* Invoke $v if it is callable, passing any extra args; otherwise return $v as-is.
204-
* Used for data variables that may hold functions (e.g. {{@hello}} or {{@hello "arg"}}).
206+
* Used for data variables that may hold functions (e.g. {{@hello}}) and for non-simple
207+
* pathed expressions with arguments (e.g. {{./helper "arg"}}).
205208
*/
206209
public static function dv(mixed $v, mixed ...$args): mixed
207210
{
208-
return $v instanceof \Closure ? $v(...$args) : $v;
211+
return $v instanceof Closure ? $v(...$args) : $v;
209212
}
210213

211214
/**
@@ -219,7 +222,7 @@ public static function dv(mixed $v, mixed ...$args): mixed
219222
public static function cv(mixed &$_this, string $name): mixed
220223
{
221224
$v = is_array($_this) ? ($_this[$name] ?? null) : null;
222-
return $v instanceof \Closure ? $v($_this) : $v;
225+
return $v instanceof Closure ? $v($_this) : $v;
223226
}
224227

225228
/**
@@ -241,18 +244,13 @@ public static function hv(RuntimeContext $cx, string $name, mixed &$_this): mixe
241244
}
242245

243246
/**
244-
* For {{#if}} and {{#unless}}.
245-
*
246-
* @param array<array<mixed>|string|int>|string|\Stringable|int|float|bool|null $v value to be tested
247-
* @param bool $zero include zero as true
248-
*
249-
* @return bool Return true when the value is not null nor false.
247+
* Returns true or false following the semantics of {{#if}} and {{#unless}} in Handlebars.js.
250248
*/
251-
public static function ifvar(mixed $v, bool $zero = false): bool
249+
public static function ifvar(mixed $v, bool $includeZero = false): bool
252250
{
253251
return $v !== null
254252
&& $v !== false
255-
&& ($zero || ($v !== 0 && $v !== 0.0))
253+
&& ($includeZero || ($v !== 0 && $v !== 0.0))
256254
&& $v !== ''
257255
&& (!is_array($v) || $v)
258256
&& (!$v instanceof \Stringable || (string) $v !== '');
@@ -300,13 +298,14 @@ public static function raw(mixed $value): string
300298

301299
/**
302300
* For {{#var}} and {{^var}} sections.
303-
* Pass null for $cb when compiling an inverted section ({{^var}}) — blockHelperMissing will call inverse().
301+
* Pass null for $cb when compiling an inverted section ({{^var}}): blockHelperMissing routes
302+
* truthy contexts through fn() (which returns '' when $cb is null) and falsy contexts through inverse().
304303
*
305304
* @param mixed $in input data with current scope
306-
* @param \Closure|null $cb callback function to render child context; null for inverted sections
307-
* @param \Closure|null $else callback function to render child context when {{else}}
305+
* @param Closure|null $cb callback function to render child context; null for inverted sections
306+
* @param Closure|null $else callback function to render child context when {{else}}
308307
*/
309-
public static function sec(RuntimeContext $cx, mixed $value, mixed $in, ?\Closure $cb, ?\Closure $else = null, ?string $helperName = null): string
308+
public static function sec(RuntimeContext $cx, mixed $value, mixed $in, ?Closure $cb, ?Closure $else = null, ?string $helperName = null): string
310309
{
311310
$helper = $helperName !== null ? ($cx->helpers[$helperName] ?? null) : null;
312311
if ($helper !== null) {
@@ -316,7 +315,7 @@ public static function sec(RuntimeContext $cx, mixed $value, mixed $in, ?\Closur
316315
// Lambda functions in block position: simple-path identifiers ($helperName set) receive
317316
// HelperOptions so they can render fn/inverse; complex paths ($helperName null) are called
318317
// with no arguments, mirroring HBS.js which does not treat them as helper calls.
319-
if ($value instanceof \Closure) {
318+
if ($value instanceof Closure) {
320319
$result = $helperName !== null
321320
? $value(new HelperOptions(scope: $in, data: $cx->data, cx: $cx, cb: $cb, inv: $else))
322321
: $value();
@@ -328,11 +327,6 @@ public static function sec(RuntimeContext $cx, mixed $value, mixed $in, ?\Closur
328327

329328
/**
330329
* Get merged context.
331-
*
332-
* @param array<array<mixed>|string|int>|object|string|int|null $a the context to be merged
333-
* @param array<array<mixed>|string|int|null>|string|int|null $b the new context to overwrite
334-
*
335-
* @return array<array<mixed>|string|int|null>|object|string|int|null the merged context object
336330
*/
337331
public static function merge(mixed $a, mixed $b): mixed
338332
{
@@ -358,7 +352,7 @@ public static function merge(mixed $a, mixed $b): mixed
358352
* @param array<string, mixed> $hash named hash overrides merged into the context
359353
* @param string $indent whitespace to prepend to each line of the partial's output
360354
*/
361-
public static function p(RuntimeContext $cx, string $name, mixed $context, array $hash, string $indent, ?\Closure $partialBlock = null): string
355+
public static function p(RuntimeContext $cx, string $name, mixed $context, array $hash, string $indent, ?Closure $partialBlock = null): string
362356
{
363357
// inlinePartials (block-scoped {{#* inline}}) take precedence over partials (persistent),
364358
// mirroring Handlebars.js which checks options.partials before env.partials.
@@ -415,9 +409,9 @@ public static function p(RuntimeContext $cx, string $name, mixed $context, array
415409
* For {{#* inline "name"}} and {{#> partial}}fallback{{/partial}} blocks.
416410
*
417411
* @param string $name partial name
418-
* @param \Closure $partial the compiled partial
412+
* @param Closure $partial the compiled partial
419413
*/
420-
public static function in(RuntimeContext $cx, string $name, \Closure $partial): string
414+
public static function in(RuntimeContext $cx, string $name, Closure $partial): string
421415
{
422416
$cx->inlinePartials[$name] = $partial;
423417
return '';
@@ -435,7 +429,7 @@ public static function dynhbch(RuntimeContext $cx, string $name, array $position
435429
}
436430

437431
$fn = $_this[$name] ?? null;
438-
if ($fn instanceof \Closure) {
432+
if ($fn instanceof Closure) {
439433
return static::hbch($cx, $fn, $name, $positional, $hash, $_this);
440434
}
441435

@@ -448,15 +442,18 @@ public static function dynhbch(RuntimeContext $cx, string $name, array $position
448442
}
449443

450444
/**
451-
* For single known helpers.
445+
* Invoke a resolved helper Closure with positional params, hash, and a HelperOptions instance.
446+
* Used for known helpers (direct hbch calls from generated code), runtime-registered helpers
447+
* (called from hv()), context closures (called from dynhbch()), and built-in fallbacks like
448+
* helperMissing/blockHelperMissing.
452449
*
453450
* @param array<mixed> $positional
454451
* @param array<string, mixed> $hash
455452
* @param mixed $_this current rendering context for the helper
456453
*/
457-
public static function hbch(RuntimeContext $cx, \Closure $helper, string $name, array $positional, array $hash, mixed &$_this): mixed
454+
public static function hbch(RuntimeContext $cx, Closure $helper, string $name, array $positional, array $hash, mixed &$_this): mixed
458455
{
459-
/** @var \WeakMap<\Closure, int>|null $paramCounts */
456+
/** @var \WeakMap<Closure, int>|null $paramCounts */
460457
static $paramCounts = null;
461458
$paramCounts ??= new \WeakMap();
462459

@@ -488,11 +485,11 @@ public static function hbch(RuntimeContext $cx, \Closure $helper, string $name,
488485
* @param array<mixed> $positional
489486
* @param array<string, mixed> $hash
490487
* @param mixed $_this current rendering context for the helper
491-
* @param \Closure|null $cb callback function to render child context (null for inverted blocks)
492-
* @param \Closure|null $else callback function to render child context when {{else}}
488+
* @param Closure|null $cb callback function to render child context (null for inverted blocks)
489+
* @param Closure|null $else callback function to render child context when {{else}}
493490
* @param array<mixed> $outerBlockParams outer block param stack for block params declared by the template
494491
*/
495-
public static function hbbch(RuntimeContext $cx, \Closure $helper, string $name, array $positional, array $hash, mixed &$_this, ?\Closure $cb, ?\Closure $else, int $blockParamCount = 0, array $outerBlockParams = []): string
492+
public static function hbbch(RuntimeContext $cx, Closure $helper, string $name, array $positional, array $hash, mixed &$_this, ?Closure $cb, ?Closure $else, int $blockParamCount = 0, array $outerBlockParams = []): string
496493
{
497494
$positional[] = new HelperOptions(
498495
scope: $_this,
@@ -513,18 +510,18 @@ public static function hbbch(RuntimeContext $cx, \Closure $helper, string $name,
513510
* @param array<mixed> $positional
514511
* @param array<string, mixed> $hash
515512
* @param array<string,array<mixed>|string|int> $_this current rendering context for the helper
516-
* @param \Closure $cb callback function to render child context
517-
* @param \Closure|null $else callback function to render child context when {{else}}
513+
* @param Closure|null $cb callback function to render main block; null for inverted sections with params/hash
514+
* @param Closure|null $else callback function to render {{else}}
518515
* @param array<mixed> $outerBlockParams outer block param stack for block params declared by the template
519516
*/
520-
public static function dynhbbch(RuntimeContext $cx, string $name, mixed $callable, array $positional, array $hash, mixed &$_this, ?\Closure $cb, ?\Closure $else, int $blockParamCount, array $outerBlockParams): mixed
517+
public static function dynhbbch(RuntimeContext $cx, string $name, mixed $callable, array $positional, array $hash, mixed &$_this, ?Closure $cb, ?Closure $else, int $blockParamCount, array $outerBlockParams): mixed
521518
{
522519
$helper = $cx->helpers[$name] ?? null;
523520
if ($helper !== null) {
524521
return static::hbbch($cx, $helper, $name, $positional, $hash, $_this, $cb, $else, $blockParamCount, $outerBlockParams);
525522
}
526523

527-
if (!$callable instanceof \Closure) {
524+
if (!$callable instanceof Closure) {
528525
return static::hbbch($cx, $cx->helpers['helperMissing'], $name, $positional, $hash, $_this, $cb, $else, $blockParamCount, $outerBlockParams);
529526
}
530527

@@ -535,7 +532,7 @@ public static function dynhbbch(RuntimeContext $cx, string $name, mixed $callabl
535532
* Resolve the return value of a block helper call:
536533
* pass through string/SafeString, stringify arrays, or delegate non-string values to blockHelperMissing.
537534
*/
538-
private static function resolveBlockResult(RuntimeContext $cx, mixed $result, mixed $_this, ?\Closure $cb, ?\Closure $else): string
535+
private static function resolveBlockResult(RuntimeContext $cx, mixed $result, mixed $_this, ?Closure $cb, ?Closure $else): string
539536
{
540537
if (is_string($result) || $result instanceof SafeString) {
541538
return (string) $result;

src/RuntimeContext.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@
22

33
namespace DevTheorem\Handlebars;
44

5+
use Closure;
6+
57
/**
68
* @internal
79
*/
810
final class RuntimeContext
911
{
1012
/**
11-
* @param array<string, \Closure> $helpers
12-
* @param array<string, \Closure> $partials compile-time and helper-registered partials (persistent)
13-
* @param array<string, \Closure> $inlinePartials block-scoped {{#* inline}} partials (reset on fn() return)
13+
* @param array<string, Closure> $helpers
14+
* @param array<string, Closure> $partials compile-time and helper-registered partials (persistent)
15+
* @param array<string, Closure> $inlinePartials block-scoped {{#* inline}} partials (reset on fn() return)
1416
* @param array<mixed> $depths
1517
* @param array<mixed> $data
1618
*/
@@ -20,6 +22,6 @@ public function __construct(
2022
public array $inlinePartials = [],
2123
public array $depths = [],
2224
public array $data = [],
23-
public ?\Closure $partialBlock = null,
25+
public ?Closure $partialBlock = null,
2426
) {}
2527
}

0 commit comments

Comments
 (0)