← All docs

Operators

Arithmetic, comparison, logical, bitwise, string, assignment, ternary, null coalescing, and error-control operators.

Arithmetic

OperatorExampleNotes
+$a + $bNumeric addition, or PHP array union when both operands are arrays. Integer overflow promotes to double.
-$a - $bSubtraction. Integer overflow promotes to double.
*$a * $bMultiplication. Integer overflow promotes to double.
/$a / $bDivision (always returns float)
%$a % $bModulo
**$a ** $bExponentiation (right-associative, returns float)
-$x-$xUnary negation

Comparison

OperatorExampleNotes
==$a == $bLoose equality using PHP-style scalar coercions for bool, null, numeric strings, and non-numeric strings
!=$a != $bLoose inequality using the same scalar coercions as ==
===$a === $bStrict equality (type and value)
!==$a !== $bStrict inequality
<$a < $bLess than
>$a > $bGreater than
<=$a <= $bLess than or equal
>=$a >= $bGreater than or equal
<=>$a <=> $bSpaceship: returns -1, 0, or 1
instanceof$obj instanceof UserRuntime class/interface check; returns bool

instanceof supports named class/interface targets plus self, parent, and static. It also supports dynamic targets such as $obj instanceof $className, $obj instanceof $otherObject, and parenthesized target expressions like $obj instanceof ($prefix . $suffix).

Direct object values and boxed mixed / nullable / union values are checked at runtime; scalar, array, and null payloads return false after the dynamic target has been validated. Dynamic string targets are matched case-insensitively against class/interface names; unknown class strings return false. Dynamic object targets use the target object’s runtime class. If a dynamic target is neither a string nor an object, the program exits with a fatal runtime diagnostic.

Bitwise

OperatorExampleNotes
&$a & $bBitwise AND
|$a | $bBitwise OR
^$a ^ $bBitwise XOR
~~$aBitwise NOT
<<$a << $bLeft shift
>>$a >> $bArithmetic right shift

Logical

OperatorExampleNotes
&&$a && $bAND with short-circuit; higher precedence than and
||$a || $bOR with short-circuit; higher precedence than or
and$a and $bWord-form AND with short-circuit; lower precedence than ?: and ??
or$a or $bWord-form OR with short-circuit; lower precedence than xor and and
xor$a xor $bWord-form exclusive OR; evaluates both operands
!!$aNOT

Word-form logical precedence matches PHP: and binds tighter than xor, and xor binds tighter than or. All three bind looser than &&, ||, ??, and the ternary operators.

Word-form logical operators are case-insensitive (AND, Or, and xOr are accepted). Assignment expressions bind tighter than and, xor, and or, matching PHP: $x = true and false is parsed as ($x = true) and false.

Error Control

PHP’s error-control operator @ suppresses runtime warnings for exactly one expression.

<?php
@file_get_contents("missing.txt");
$value = @file_get_contents("missing.txt");
echo "still running";

The operand is evaluated normally and its value is preserved. Only suppressible runtime warnings are hidden; compile-time errors and fatal runtime errors still report normally. Nested @ scopes are tracked with a runtime suppression depth, and exception unwinds restore the previous suppression state before entering a catch.

print is supported as a PHP-compatible expression: it writes its operand to stdout and returns 1.

<?php
$status = print "ready\n";
echo $status;          // 1
echo print "nested";   // nested1

Its precedence matches PHP: the operand can include ?: and ??, while the word-form logical operators and, xor, and or bind looser than the whole print expression.

String

OperatorExampleNotes
."a" . "b"Concatenation
."val=" . 42Auto-coerces int to string
."pi=" . 3.14Auto-coerces float to string

Assignment

OperatorExampleEquivalent
=$x = 5Simple assignment
+=$x += 5$x = $x + 5
-=$x -= 5$x = $x - 5
*=$x *= 5$x = $x * 5
**=$x **= 5$x = $x ** 5
/=$x /= 5$x = $x / 5
%=$x %= 5$x = $x % 5
.=$s .= "x"$s = $s . "x"
&=$x &= 5$x = $x & 5
`=``$x
^=$x ^= 5$x = $x ^ 5
<<=$x <<= 2$x = $x << 2
>>=$x >>= 2$x = $x >> 2
??=$x ??= "default"Assign RHS only when $x is null

Compound assignments are supported for local variable assignments, for init/update clauses, object properties, static properties, indexed array elements, property-backed indexed array elements, and static-property-backed indexed array elements:

$items[0] += 3;
$box->count *= 2;
$box->items[1] >>= 1;
Counter::$count **= 2;
Registry::$items[0] ??= 10;

Append targets such as $items[] += 1 are invalid; append syntax is only supported with plain assignment ($items[] = 1). Receiver and index expressions are evaluated once for non-local compound targets, matching PHP read-modify-write behavior for forms such as $items[f()] += 1 and getBox()->count += 1.

Local variable assignments can also be used as expressions. The expression returns the assigned value and still updates the local:

<?php
echo ($x = 5);      // 5
echo $x;            // 5

$x = true and false;
echo $x ? "T" : "F"; // T

$count = 4;
echo ($count += 3); // 7

Assignment expression precedence matches PHP: assignment binds lower than ?: and ??, but higher than the word-form logical operators. The expression form supports local variables plus stabilized non-local targets such as array elements, object properties, static properties, and indexed array slots stored in properties:

<?php
$items = [1, 2];
echo ($items[1] = 5); // 5

class Box {
    public $count = 1;
    public $items = [2];
}
$box = new Box();
echo ($box->count += 4);
echo ($box->items[0] *= 3);

class Registry {
    public static ?int $value = null;
}
echo (Registry::$value ??= 10);

Non-local assignment expression targets stabilize receiver and index subexpressions when needed, so side-effecting targets such as $items[idx()] = 1 and make_box()->count += 1 are evaluated once. For = and compound assignment, elephc also preserves PHP’s ordering for RHS-mutated simple indexes such as $items[$i] = ($i = 1) while pre-evaluating computed indexes such as $items[$i + 0] = ($i = 1).

For ??= expression form, elephc preserves the PHP short-circuit rule and the conditional write order for non-local targets. If the current target value is non-null, the right-hand side is not evaluated. If it is null, the right-hand side runs before the final write target is evaluated, so forms such as $items[$i] ??= ($i = 1) write through the updated simple index while computed/effectful index parts remain stabilized.

List Unpacking

<?php
[$a, , $c] = [10, 20, 30];
echo $a;  // 10
echo $c;  // 30

list($left, $right) = [1, 2];
echo $left . $right; // 12

Destructuring supports skipped entries, nested patterns, associative keys, short syntax ([...]), and list(...) syntax. Targets may be local variables or the same writable non-local forms ordinary assignment supports, such as array slots, append targets, object properties, and static properties.

<?php
[[$a, $b], [$c, $d]] = [[1, 2], [3, 4]];
["id" => $id, "name" => $name] = ["name" => "Ada", "id" => 7];
[$items[0], $items[]] = [5, 6];

As in PHP, keyed and unkeyed entries cannot be mixed in the same destructuring pattern.

Null Coalescing

$x = null;
echo $x ?? "default";    // prints "default"
echo $x ?? $y ?? "last"; // chained — right-associative

$x ??= "fallback";       // assigns because $x is null
$x ??= "ignored";        // keeps "fallback"; RHS is not evaluated

??= is supported for already-declared local/global/static variables and non-append property/array/static-property assignment targets as a standalone assignment statement. For concrete local variable types, the fallback must keep the same static type, or be a literal null. Use a nullable, union, or mixed typed local when the fallback may change the stored runtime representation.

Nullsafe Access

<?php
echo $user?->profile?->name ?? "anonymous";
echo $user?->profile?->label() ?? "missing";
echo $user?->profile->address?->city ?? "unknown";

?-> supports nullable object property access and method calls. If the receiver is null, elephc skips the rest of the current postfix chain and the expression returns null; method arguments, array indexes, and callable arguments on that skipped branch are not evaluated. Mixed chains such as $user?->profile->address match PHP: ->address is skipped when $user is null, but still warns or fatals normally if $user is non-null and profile itself is null. Use ?? when you want to provide a fallback value.

Nullsafe access cannot be used as an assignment target or combined with first-class callable creation, matching PHP.

Increment / Decrement

OperatorExampleReturns
++$iPre-incrementNew value
$i++Post-incrementOld value
--$iPre-decrementNew value
$i--Post-decrementOld value

Ternary

$max = $a > $b ? $a : $b;
$label = $name ?: "anonymous";

The short ternary / Elvis form expr ?: fallback returns the original left-hand value when it is truthy, otherwise it evaluates and returns the fallback. The left-hand expression is evaluated once.

Pipe (PHP 8.5)

The pipe operator |> invokes its right-hand callable with the left-hand value as the single positional argument. $x |> foo(...) is equivalent to foo($x). The left-hand side is evaluated before the right-hand side, and chained pipes apply left-to-right.

$result = "hello world"
    |> strtoupper(...)
    |> strrev(...);
// equivalent to: strrev(strtoupper("hello world"))

The right-hand side may be any expression that evaluates to a callable:

  • First-class callable syntax: foo(...), Class::method(...), $obj->method(...)
  • A closure literal: (fn($v) => $v + 1)
  • A variable holding a callable: $cb
  • Any other expression returning a callable

The callable must accept the piped value as its first parameter; remaining parameters must be optional or variadic. By-reference parameters are not supported on the pipe target.

First-class callable creation accepts local receivers such as $obj->method(...) and $this->method(...), plus non-local receiver expressions such as (new Greeter())->greet(...) or (getThing())->method(...). The receiver expression is evaluated when the callable is created, then captured in the generated wrapper.

$cb = (new Greeter())->greet(...);
$value |> $cb;

Precedence is left-associative and sits below concatenation (.), bit shifts, and the additive operators (+, -). Comparisons, ??, ternary, logical operators, and assignment all bind looser than |>:

echo 5 + 2 |> double(...);          // (5 + 2) |> double(...)
echo "a" . "b" |> wrap(...);        // ("a" . "b") |> wrap(...)
echo "beep" |> strlen(...) == 4;    // (...|> strlen(...)) == 4
echo $id |> get(...) ?? "default";  // (...|> get(...)) ?? "default"