tacoberu / hayo
Lightweight purely functional scripting runtime with static typing and type inference.
Requires
- php: >=7.4
- tacoberu/hayo-decoder: ~0.3.13
Requires (Dev)
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^11.5
- rector/rector: ^2.2
- slevomat/coding-standard: ^8.24
- spaze/phpstan-disallowed-calls: ^4.6
- tracy/tracy: ^2.7
This package is auto-updated.
Last update: 2026-06-03 03:07:14 UTC
README
Hayo is a lightweight, purely functional scripting language / runtime implemented in PHP. It is designed for interpreting user-defined logic (conditions, transformations, business rules) from scripts that you may want to store (for example) in a database and keep user-editable. You pass a script as a string, compile it into a function, and then call that function with concrete data.
Read the language syntax reference and the built-in function reference.
π‘ Why Hayo?
- π‘οΈ Security by Isolation: Purely functional, no side-effects. Scripts have zero access to the filesystem, network, or global PHP state. It is a safe way to run user-provided logic.
- πΎ Persistence & Caching: Compiled, optimized bytecode can be transparently cached. The result is already a fast function.
- π§ Expressiveness: The language supports local variables, lambdas, and pattern matching.
- π Static Analysis: Includes type inference and compile-time validation to catch most embarrassing errors.
π Quick Start
composer require tacoberu/hayo
use Taco\Hayo\HayoEngine; $engine = HayoEngine::WithDefaultLibraries(); // Simple evaluation $engine->evaluate("1 + 1"); // 2 // With arguments $engine->evaluate("a + b", ["a" => 1, "b" => 2]); // 3
π‘ Real-world Example: Business Logic
Hayo elegantly handles complex branching and data transformations:
-- Calculate total from an array of dictionaries
totalPrice = order.items
|> List.map (i -> i.price * i.quantity)
|> List.fold 0 (acc curr -> acc + curr)
-- Condition with branching and pattern matching
if totalPrice > 1000 or order.customer.isVip then
totalPrice * 0.9 -- 10% discount
else
totalPrice
β Comparison with Alternatives
The most common alternative for PHP is Symfony Expression Language. Below is how they compare:
| Feature | Hayo | Symfony Expression Language |
|---|---|---|
| Custom functions | β | β |
| Local variables in script | β | β οΈ injection only |
| Lambdas / Closures | β | β |
| Map / fold / filter | β | β οΈ via extensions |
| Branching (if-else) | β | β οΈ ternary only |
| Pattern Matching (match) | β | β |
| Type Inference | β | β |
π Usage & Integration
Bytecode caching
For repeated execution, use a cache adapter to avoid re-compiling the script:
$engine->setCache(new MyCacheAdapter()) ->evaluate("1 + a", ["a" => 1]);
Custom function libraries
You can extend Hayo with your own PHP-defined functions.
$engine->registerLibrary("MyStrings", new MyStringsProvider()) ->evaluate('MyStrings.format("result: ${0}", [1 + a])', ["a" => 1]);
Local functions and lambdas
You can define functions within your script:
HayoEngine::WithDefaultLibraries() ->evaluate(" inc = x -> x + 1 inc counter ", ["counter" => 41]); // 42
Higher-order functions β map, fold, and more
HayoEngine::WithDefaultLibraries() ->evaluate("List.map xs (x -> x * x)", ["xs" => [1, 2, 3]]); // [1, 4, 9]
Pipe chains operator
HayoEngine::WithDefaultLibraries() ->evaluate(" xs |> List.map (x -> x * x) |> List.fold 0 (prev curr -> prev + curr) ", ["xs" => [1, 2, 3, 4]]); // 30
β οΈ Exceptions
The engine distinguishes between three phases where an error can occur:
Compilation Errors
Occur during evaluate() or compile().
CompileException: Syntax error in the script β invalid source code, unrecognized token, incomplete expression, or unresolved expression.SymbolNotFound: Script refers to a symbol, built-in, or library function that is not available in the runtime (not registered or a typo in the name).
Argument Errors
Occur when calling a compiled script with concrete data.
ArgumentsException: Script was called with wrong parameters β wrong name, count, or value type.
Runtime Errors
Occur during script execution.
ScriptRuntimeException: Any error during execution β wrong argument type for a built-in function, division by zero (div, mod), etc. Wraps all Throwables that occurred during evaluation. The original cause is available via getPrevious().
π Built-in Functions
Read the complete built-in function reference.
- Math:
+,-,*,div,mod,Math.ceil,Math.floor,Math.round. - Strings (Str):
len,split,concat,format,indexOf,contains,startsWith,endsWith,sub,toUpper,toLower,trim. - Lists (List):
len,first,at,exist,concat,push,indexOf,slice,split,map,fold,filter,sort. - Dictionaries (Dict):
has,get,merge,keys,values. - DateTime:
fromDate,fromDateTime,fromTimestamp,toTimestamp,format. - Introspect:
of,is.
Architecture
hayo-ast: AST node definitions.hayo-parser: Default recursive descent parser.hayo: Runtime and compiler for PHP.