← All docs

Functions

Function declarations, closures, arrow functions, variadic parameters, and more.

Declaration and calls

<?php
function add($a, $b) {
    return $a + $b;
}
echo add(3, 4); // 7

Function lookup is case-insensitive like PHP. The declaration keeps its original name, but calls such as ADD(3, 4), Add(3, 4), and add(3, 4) resolve to the same function. Built-in function names follow the same rule.

Parameter and return type hints

<?php
function repeat(string $label, int $count): string {
    return $label . $count;
}
  • Supported types: int, float, bool, string, array, mixed, iterable, callable, ptr, buffer<T>, class/interface/enum names, unions, and nullable forms
  • void is valid only as a return type
  • never is valid only as a return type and must not return normally
  • Typed parameters can use default values
  • Function, method, constructor, closure, and arrow-function parameter hints are checked
  • Function, method, closure, and arrow-function return type hints are checked
  • Variadic parameters are supported only without a parameter type hint for now; function f(int ...$xs), typed variadic methods, typed variadic closures, and typed variadic arrow functions are rejected.
  • Non-void declared return types must return a value on every reachable path; throw, exit()/die(), and infinite loops count as non-returning paths
  • Bare return; is valid only for void returns; use return null; for nullable return types
  • Named arguments are supported for known-signature calls: user-defined functions, methods, closures, built-ins, and extern functions
  • Argument expressions are evaluated in PHP source order, then codegen normalizes the resulting values into ABI parameter order
  • Named arguments can follow spread arguments, as in foo(...$args, suffix: "!"); positional arguments cannot follow either named arguments or spread arguments
  • Associative-array unpacking maps string keys to named arguments (foo(...["name" => "Ada"])) and keeps numeric keys positional. Variable associative-array spreads can satisfy any parameter by string key, including parameters after explicit named arguments. Duplicate static string keys use PHP’s last-wins behavior before argument planning.
  • A positional spread into a variadic function fills regular parameters first; only excess spread elements are collected into the variadic parameter. If a spread is too short to fill required parameters, the call fails instead of reading beyond the array payload.
  • User-defined variadic functions collect unknown named arguments into the variadic parameter using string keys
  • Built-in variadic functions reject unknown named arguments, matching PHP’s internal-function behavior

Recursion

<?php
function factorial($n) {
    if ($n <= 1) { return 1; }
    return $n * factorial($n - 1);
}
echo factorial(10); // 3628800

Default parameter values

<?php
function greet($name = "world") {
    echo "Hello " . $name . "\n";
}
greet();        // Hello world
greet("PHP");   // Hello PHP

Parameters with defaults must come after required parameters.

Local scope

Variables inside a function are separate from the caller.

Anonymous functions (closures)

<?php
$double = function(int $x): int {
    return $x * 2;
};
echo $double(5); // 10

Closures can capture with use:

<?php
$factor = 3;
$multiply = function(int $x) use ($factor): int {
    return $x * $factor;
};
echo $multiply(5); // 15

Use & in the capture list when the closure must share and mutate the outer variable, including recursive anonymous functions:

<?php
$factorial = null;
$factorial = function($n) use (&$factorial) {
    return $n <= 1 ? 1 : $n * $factorial($n - 1);
};
echo $factorial(5); // 120

Captured closures can also be used as callback values:

<?php
$factor = 3;
$values = array_map(function(int $x) use ($factor): int {
    return $x * $factor;
}, [1, 2, 3]);
echo $values[2]; // 9

Static closures

A closure prefixed with static does not capture $this from its enclosing scope. This matches PHP’s static function () {} and static fn () => ... — useful when a closure is meant to be unbound (often paired with Closure::bind(..., null, ...)):

<?php
$add = static function ($a, $b) {
    return $a + $b;
};
echo $add(3, 4);                     // 7

$double = static fn ($x) => $x * 2;
echo $double(5);                     // 10

Inside a static closure, referencing $this is a compile-time error:

<?php
class C {
    public int $count = 5;
    public function bad() {
        // Error: Cannot use $this inside a static closure
        return static function () { return $this->count; };
    }
}

Arrow functions

<?php
$double = fn(int $x): int => $x * 2;
echo $double(5); // 10

$nums = [1, 2, 3, 4];
$squared = array_map(fn(int $n): int => $n * $n, $nums);

First-class callable syntax

<?php
$triple = triple(...);
$double = MathBox::double(...);

Supported: user-defined function names, extern function names, ClassName::method(...), self::method(...), parent::method(...), and registered builtin wrappers. Builtin wrapper coverage includes common string transforms and searches (strlen(...), trim(...), substr(...), str_contains(...)), casts and type checks (intval(...), floatval(...), gettype(...), is_int(...)), math helpers (abs(...), sqrt(...), round(...)), JSON helpers, and array helpers including count(...), array_sum(...), array_product(...), and by-reference mutators such as sort(...). Also supported: static::method(...) inside class methods, preserving late static binding for direct callable calls, and $obj->method(...) / $this->method(...) with either a local receiver variable or a non-local receiver expression such as (new Greeter("Hi "))->greet(...).

<?php
class Greeter {
    public function hello($name) {
        return "Hello " . $name;
    }
}

$greeter = new Greeter();
$hello = $greeter->hello(...);
echo $hello("Ada"); // Hello Ada

Captured first-class callable targets (static::method(...) and $obj->method(...)) can be called directly through a local callable variable or as an immediate callable expression such as ($obj->method(...))("Ada"). They can also be passed to callback paths that forward captured callable environments, including array_map(), array_filter(), array_reduce(), array_walk(), usort(), uksort(), uasort(), call_user_func(), and call_user_func_array(). For by-reference callback parameters, call_user_func_array() supports literal argument arrays whose by-reference positions are variables, such as call_user_func_array($cb, [$value]). PHP disallows nullsafe first-class callable syntax ($obj?->method(...)), and elephc reports the same error.

Global variables

<?php
$x = 10;
function test() {
    global $x;
    echo $x;    // 10
}

Static variables

<?php
function counter() {
    static $n = 0;
    $n++;
    echo $n . "\n";
}
counter(); // 1
counter(); // 2

Pass by reference

<?php
function increment(&$val) {
    $val++;
}
$x = 5;
increment($x);
echo $x; // 6

Variadic functions

<?php
function sum(...$nums) {
    $total = 0;
    foreach ($nums as $n) {
        $total += $n;
    }
    return $total;
}
echo sum(1, 2, 3); // 6

Variadic parameters can appear on functions, methods, closures, and arrow functions, but the variadic parameter itself cannot carry a type hint yet. Use function sum(...$nums) instead of function sum(int ...$nums).

Spread operator

<?php
$args = [10, 20, 30];
echo sum(...$args); // 60

$a = [1, 2];
$b = [3, 4];
$c = [...$a, ...$b]; // [1, 2, 3, 4]

Call unpacking follows PHP’s parameter mapping. Spread values fill regular positional parameters before any variadic tail is built, and associative-array spreads treat string keys as named arguments:

<?php
function show($a, $b = 99, ...$rest) {
    echo $a . ":" . $b . ":" . count($rest);
}

show(...[10]);                    // 10:99:0
show(...[10, 20, 30]);            // 10:20:1
show(...[10, "b" => 20]);         // 10:20:0

$args = ["b" => 20, "a" => 10];
show(...$args);                   // 10:20:0

$args = ["b" => 20];
show(...$args, a: 10);            // 10:20:0

echo

echo is a PHP language construct statement. It writes each operand to stdout using PHP scalar output rules and accepts PHP-compatible comma-separated operands:

<?php
echo "Hello", ", ", "World!\n";

print

print is a PHP language construct expression. It writes its operand to stdout using the same scalar output rules as echo, then returns 1.

<?php
$ok = print "ready\n";
echo $ok;             // 1

echo print "nested";  // prints "nested1"

As in PHP, print can also stand alone as a statement:

<?php
print "hello\n";