Expression Trees: Splicing

Expression trees support "splicing", where you insert one expression tree into another.

<<file:__EnableUnstableFeatures('expression_trees')>>

function splicing_example(bool $b): ExprTree<ExampleDsl, mixed, ExampleString> {
  $name = $b ? ExampleDsl`"world"` : ExampleDsl`"universe"`;
  return ExampleDsl`"Hello, ".${$name}."!"`;
}

This allows you to build different expressions based on runtime values. DSL expressions are not evaluated, but the value in the ${...} is evaluated and inserted into the expression tree.

The above example is equivalent to this:

<<file:__EnableUnstableFeatures('expression_trees')>>

function splicing_example2(bool $b): ExprTree<ExampleDsl, mixed, ExampleString> {
  return $b ? ExampleDsl`"Hello, "."world"."!"` : ExampleDsl`"Hello, "."universe"."!"`;
}

Limitations

Every DSL expression must be valid in isolation. You cannot use free variables in expression trees, even when splicing.

$var = ExampleDsl`$x`; // type error: $x is not defined
ExampleDsl`($x) ==> { return ${$var}; }`;

Implementing Splicing

A visitor needs to support the splice method to allow splicing. The splice method is passed the inner expression tree value, along with a unique key that may be used for caching visitor results.

final class MyDsl {
  public function splice(
    ?ExprPos $_pos,
    string $_key,
    Spliceable<MyDsl, MyDslAst, mixed> $code,
  ): MyDslAst {
    return $code->visit($this);
  }

  // ...
}

For more information, see: Defining Visitors: Spliceable Types.

Was This Page Useful?
Thank You!
Thank You! If you'd like to share more feedback, please file an issue.