Language reference
Everything HolyPHP adds on top of PHP — and everything it borrows from Rust. All snippets are verified against the compiler.
Variables & types
Variables are PHP-style: start with $, no declaration keyword, inferred types.
Add an explicit type after the name when you want one.
$count = 5; // inferred int
$pi = 3.14159; // float
$ok = true; // bool
$who = "Elias"; // string
$count: int = 5; // pinned types
$rate: float = 0.19;
$name: string = "Ann";
$flag: bool = false;
$items = [1, 2, 3]; // list array
$user = ["name" => "Elias", // map array (string keys)
"lang" => "HolyPHP"];
| Type | Literals | Notes |
|---|---|---|
int | 42, 0x2A | 64-bit signed |
float | 3.14, 1e9 | 64-bit IEEE |
bool | true / false | |
string | "..." with {$var} interpolation | immutable, refcounted |
array | [1, 2], ["k" => "v"] | copy-on-write value semantics |
mixed | anything | runtime-tagged hval |
Functions
Fully typed signatures with optional parameters and defaults. Untyped functions are inferred like scripts.
function greet(string $who): string {
return "Hi, {$who}!";
}
function pow2(float $base, int $exp = 2): float {
return $base ** $exp;
}
// by-reference parameter (a mutable borrow)
function bump(int &$r): void { $r += 1; }
$n = 41;
bump($n); // $n === 42
Operators
| Group | Operators |
|---|---|
| Arithmetic | + - * / % ** |
| String | . concat, .= append |
| Comparison | == != === !== < > <= >= <=> |
| Logic | && || ! |
| Bitwise | & | ^ << >> |
| Null coalesce | ?? |
| Compound | += -= *= /= %= .= **= |
| Increment | ++ -- (prefix and postfix) |
| Ternary | cond ? a : b |
Control flow
if ($n < 2) { return $n; }
elseif ($n == 2) { echo "two\n"; }
else { echo "many\n"; }
while ($i < 10) { $i++; }
for ($i = 0; $i < 10; $i++) { echo $i; }
foreach ($nums as $x) { $total += $x; }
foreach ($user as $k => $v) { echo "{$k} => {$v}\n"; }
match — algebraic switching
function classify(int $n): string {
return match ($n) {
0 => "zero",
1, 2, 3 => "small",
_ => "big",
};
}
Classes & OOP
Visibility is explicit: pub (public), private, static
for fields. Methods inherit PHP-style; constructors may be inherited too.
class Counter {
pub int $count = 0; // field with default
private $secret = "s";
pub function __construct(int $start = 0) {
$this->count = $start;
}
pub function bump(): void {
$this->count += 1;
}
pub function get(): int {
return $this->count;
}
}
$c = new Counter(10);
$c->bump();
echo $c->get(); // 11
class Animal {
pub function speak(): string { return "..."; }
}
class Dog extends Animal {
pub function speak(): string { return "Woof!"; }
}
echo (new Dog())->speak(); // "Woof!" — dynamic dispatch
Closures & captures
Closures capture PHP-style with use. By-value copies by default;
use (&$x) captures by reference — the variable lives in a heap box
shared with the outer scope.
$base = 100;
$addBase = function(int $x) use ($base): int { // by value
return $base + $x;
};
$clicks = 0;
$onClick = function() use (&$clicks): void { // by reference
$clicks = $clicks + 1; // outer $clicks changes
};
$onClick(); $onClick();
echo $clicks; // 2
mixed, so the same slot is shared — no dangling pointers, no
data races, verified by hphp check.Exceptions
try {
throw "boom";
} catch (string $e) {
echo "caught: {$e}\n";
} finally {
echo "always runs\n";
}
throw accepts a value (strings today, Exception objects too). Handlers are
invoked through a setjmp-free architecture — the runtime runs each protected block as a
helper, so no volatile tricks appear in generated code and -O2 is safe.
Enums
enum Farbe: int { Rot, Gruen, Blau }
function colorName(Farbe $f): string {
return match ($f) {
Farbe::Rot => "red",
Farbe::Gruen => "green",
Farbe::Blau => "blue",
};
}
Memory model
HolyPHP is memory-safe by default and low-level when you ask.
| Concept | Syntax | Meaning |
|---|---|---|
| Value semantics | plain assignment | scalars & arrays copy-on-write |
| Immutable borrow | &$x | read-only alias, many allowed |
| Mutable borrow | &mut $x | exactly one at a time |
| Owned box | own<T> | exclusive ownership, moves |
| Shared pointer | Rc<T> | refcounted shared ownership |
| Raw pointer | *T / &$x under unsafe | only inside unsafe {} |
// borrow checker at compile time:
function laenge(string $text): int { // takes an immutable borrow
return strlen($text);
}
$w = "borrowed";
echo laenge($w); // owner keeps $w
// this is a compile ERROR (two mutable borrows):
// function bump(int &$r): void { $r += 1; }
// bump(&$n); bump(&$n); ... => rejected by hphp check
unsafe {
$geheim: int = 42;
$zeiger: &int = &$geheim; // raw pointer
echo "deref = " . (*$zeiger) . "\n";
}
Imports & the stdlib
Libraries ship inside the compiler binary — import finds them with no files
on disk.
import "ui.hphp"; // desktop GUI toolkit
import "websocket.hphp"; // RFC 6455 server
Strings
Immutable and refcounted; interpolation is compile-time parsed into concat calls.
$name = "Elias";
echo "Hi {$name}, you have " . (3 + 4) . " new messages\n";
$s = "Hello";
$s .= " World"; // append (rebuilt behind the scenes)
Arrays & maps
One type for both: lists keep insertion order; assigning a string key or a non-sequential int key promotes to a keyed map (exactly PHP's semantics).
$nums = [5, 3, 8, 1, 9];
$nums[] = 7; // append
sort($nums); // in place
echo $nums[0]; // 1
$m = [];
$m[1] = "a"; // key 1 is remembered
$m["name"] = "Elias"; // becomes a keyed map
foreach ($m as $k => $v) {
echo "{$k} => {$v}\n"; // 1 => a, then name => Elias
}
$a = [1, 2, 3];
$b = $a; // COW: shares until one writes
$b[0] = 99; // clones now; $a unchanged