Expressions And Operators: Function Call

A function is called using the () operator, which optionally contains a comma-separated list of expressions called arguments. Consider the following function definition and call:

newtype Point = (float, float);

function create_point(float $x, float $y): Point {
  return tuple($x, $y);

function distance(Point $p1, Point $p2): float {
  $dx = $p1[0] - $p2[0];
  $dy = $p1[1] - $p2[1];
  return \sqrt($dx * $dx + $dy * $dy);

function main(): void {
  echo "Distance is ".distance(tuple(3.5, -6.2), tuple(-2.4, 3.6))."\n";
Distance is 11.438968484964

Here, the function distance is called from main using the called-function's name followed by the function-call operator containing a list of two arguments. Each argument corresponds by position to a parameter in the called function's definition. An argument can have any type that is compatible with the corresponding parameter. In a function call, the arguments are evaluated in the order left-to-right. This is important to understand if any of the argument values contains side-effects; for example:

distance(tuple($v++, -6.2), tuple(-$v, 3.6))

Ordinarily, the function-call operator is preceded by the name of the function to be called; however, what that operator really needs is an expression that designates a function, and alternative approaches are available beside using that function's name. Consider the following example, which indexes into an array of anonymous-function objects, and calls the resulting unnamed function:

function main(): void {
  $table = vec[
    (int $p) ==> $p * 2, // doubler
    (int $p) ==> $p * 3, // tripler
    (int $p) ==> $p * 4, // quadrupler

  $seq = new Sequence();

  $v = $table[$seq->next()]($seq->next()); // eval is L-to-R
  echo "\$v = $v\n";

  $v = $table[$seq->next()]($seq->next()); // eval is L-to-R
  echo "\$v = $v\n";

class Sequence {
  private int $last = -1;
  public function next(): int {
    return $this->last;
$v = 2
$v = 12

In the function call,


the expression designating the function is evaluated before the expressions in the argument list, so given that $seq->next() has not been called before, the call is


which calls the doubler function, which returns 1x2=2.

In the second call,


given that $i has been called twice, the call is


which calls the quadrupler function and results in 3x4=12.

When a function is called, the value of each argument passed to it is assigned to the corresponding parameter in that function's definition, if such a parameter exists. Any parameter having a default value, but no corresponding argument, takes on that default value. For example:

function f3(int $p1 = -1, float $p2 = 99.99, string $p3 = '??'): void { ... }
f3();                   // $p1 is -1, $p2 is 99.99, $p3 is ??
f3(123);                // $p1 is 123, $p2 is 99.99, $p3 is ??
f3(123, 3.14);          // $p1 is 123, $p2 is 3.14, $p3 is ??
f3(123, 3.14, 'Hello'); // $p1 is 123, $p2 is 3.14, $p3 is Hello

If the called function is variadic, the function call can have any number of arguments, provided the function call has at least an argument for each parameter not having a default value. When an argument corresponds to the ellipsis in the called function's definition, the argument can have any type.

Direct and indirect recursive function calls are permitted. For example:

function factorial(int $i): int {
  if ($i > 1) return $i * factorial($i - 1);
  else if ($i === 1) return $i;
  else return 0;

When an instance method or constructor is called, the instance used becomes the value of $this in the invoked method or constructor. However, if no instance was used (for example, in the call C::instance_method()) the invoked instance has no $this defined.

By default, arguments are passed by value; however, if a parameter contains the inout modifier, the corresponding argument must also contain that modifier. See the swap function in defining a function for an example.