PHP Operators
What Is an Operator? In simple terms: An operator is a symbol (or keyword) that tells PHP to do something with one or more values — add them, compare them, combine them, or assign them to a variable.
What Is an Operator?
In simple terms: An operator is a symbol (or keyword) that tells PHP to do something with one or more values — add them, compare them, combine them, or assign them to a variable.
Technically: An operator takes one or more operands (values or expressions) and produces a new value. The combination of operators and operands is an expression.
$total = $price * $quantity;
| Part | Role |
|---|---|
$price, $quantity | Operands |
* | Multiplication operator — produces the product |
= | Assignment operator — stores the result in $total |
$price * $quantity | An expression; its value is the product |
Why Operators Matter
Almost every line of a program uses operators: calculating totals, checking conditions, building strings, combining flags, and providing default values. Understanding what each operator does — and which operator is evaluated first — is essential for writing correct expressions.
Operators by Number of Operands
| Kind | Operands | Examples |
|---|---|---|
| Unary | One | -$x (negation), !$flag (not), ++$i (increment) |
| Binary | Two | $a + $b, $a === $b, $a && $b |
| Ternary | Three | $condition ? $ifTrue : $ifFalse |
Operator Categories
PHP's operators are grouped by purpose. Most categories have their own lesson, listed in the last column.
| Category | Operators | Purpose | Lesson |
|---|---|---|---|
| Arithmetic | + - * / % ** | Mathematical calculations | Arithmetic Operators |
| Assignment | = += -= *= /= .= ??= … | Store and update values | Assignment Operators |
| Comparison | == === != !== < > <= >= | Compare values, producing true/false | Comparison Operators |
| Spaceship | <=> | Three-way comparison (-1, 0, 1) | Spaceship Operator |
| Increment / Decrement | ++ -- | Add or subtract 1 | Increment / Decrement Operators |
| Logical | && || ! and or xor | Combine conditions | Logical Operators |
| String | . .= | Join strings | Concatenate Strings |
| Null coalescing | ?? | Default for null or missing values | Null Coalescing Operator |
| Conditional (ternary) | ?: | Choose between two values | PHP Shorthand if |
| Array | + == === != !== | Combine and compare arrays | This lesson |
| Bitwise | & | ^ ~ << >> | Work with individual bits | This lesson |
| Type | instanceof | Check an object's class | This lesson |
| Nullsafe | ?-> | Access members when the object may be null | Nullsafe Operator |
| Pipe | |> | Pass a value through a chain of functions (PHP 8.5+) | This lesson |
| Error control | @ | Suppress error messages (avoid) | This lesson |
| Execution | `command` | Run a shell command (avoid) | This lesson |
A Quick Tour
Example
<?php
$price = 450;
$quantity = 3;
$coupon = null;
$age = 20;
$subtotal = $price * $quantity; // arithmetic
$subtotal -= 50; // compound assignment
$label = "Total: ₹" . $subtotal; // string concatenation
$isAdult = $age >= 18; // comparison
$canBuy = $isAdult && $subtotal > 0; // logical
$code = $coupon ?? 'NONE'; // null coalescing
$status = $canBuy ? 'Allowed' : 'Blocked'; // ternary
echo $label . "\n";
var_dump($isAdult, $canBuy);
echo "Coupon: $code\n";
echo "Status: $status\n";
Output
Total: ₹1300
bool(true)
bool(true)
Coupon: NONE
Status: Allowed
How Each Line Works
*multiplies450 × 3 = 1350.-=subtracts 50 from$subtotaland stores the result (1300)..joins text and the number into one string.>=compares and produces a boolean.&&istrueonly if both conditions are true.??returns the left side unless it isnull(or undefined); here it returns'NONE'.?:chooses'Allowed'because$canBuyis true.
Operator Precedence and Associativity (Introduction)
When an expression contains several operators, precedence decides which is evaluated first, just like multiplication before addition in mathematics.
<?php
echo 2 + 3 * 4 . "\n";
echo (2 + 3) * 4 . "\n";
Output
14
20
* has higher precedence than +, so 3 * 4 is calculated first. Parentheses override precedence.
Associativity decides the order when operators have the same precedence:
<?php
echo 20 - 5 - 3 . "\n"; // left-associative: (20 - 5) - 3
echo 2 ** 3 ** 2 . "\n"; // right-associative: 2 ** (3 ** 2)
Output
12
512
The full precedence table and its practical consequences are covered in Operator Precedence. The most useful rule: when in doubt, add parentheses. They cost nothing and make intent obvious.
Array Operators
Arrays have their own meaning for + and the comparison operators.
| Operator | Name | Result |
|---|---|---|
$a + $b | Union | $a plus elements of $b whose keys are not already in $a |
$a == $b | Equality | true if both have the same key/value pairs (values compared loosely) |
$a === $b | Identity | true if same key/value pairs, in the same order, with the same types |
$a != $b, $a <> $b | Inequality | Opposite of == |
$a !== $b | Non-identity | Opposite of === |
Union With +
<?php
$defaults = ['theme' => 'light', 'lang' => 'en', 'perPage' => 20];
$userSettings = ['lang' => 'ta', 'perPage' => 50];
print_r($userSettings + $defaults);
Output
Array
(
[lang] => ta
[perPage] => 50
[theme] => light
)
The union keeps every key from the left array and adds only the missing keys from the right. This makes $userSettings + $defaults a concise way to fill in default options.
The Union Trap With Indexed Arrays
<?php
print_r([1, 2] + [3, 4, 5]);
Output
Array
(
[0] => 1
[1] => 2
[2] => 5
)
Both arrays have keys 0 and 1, so only key 2 (value 5) is added from the right. + does not append lists. To combine lists, use array_merge() or the spread operator ([...$a, ...$b]), covered in Merge Arrays and Array Spread Operator.
Comparing Arrays
<?php
$a = ['id' => 1, 'name' => 'Asha'];
$b = ['name' => 'Asha', 'id' => 1];
$c = ['id' => '1', 'name' => 'Asha'];
var_dump($a == $b); // same pairs, different order
var_dump($a === $b); // order differs
var_dump($a == $c); // '1' == 1
var_dump($a === $c); // types differ
Output
bool(true)
bool(false)
bool(true)
bool(false)
Bitwise Operators
Bitwise operators work on the individual bits (binary digits) of integers. They are less common in everyday web code but appear in flags, permissions, error levels, and low-level data processing.
| Operator | Name | Result |
|---|---|---|
$a & $b | AND | Bits set in both |
$a | $b | OR | Bits set in either |
$a ^ $b | XOR | Bits set in one but not both |
~$a | NOT | All bits inverted |
$a << $n | Shift left | Bits moved left $n places (multiply by 2ⁿ) |
$a >> $n | Shift right | Bits moved right $n places (divide by 2ⁿ, rounding down) |
Example: Bit Arithmetic
<?php
printf("6 & 3 = %d (%04b & %04b = %04b)\n", 6 & 3, 6, 3, 6 & 3);
printf("6 | 3 = %d (%04b | %04b = %04b)\n", 6 | 3, 6, 3, 6 | 3);
printf("6 ^ 3 = %d (%04b ^ %04b = %04b)\n", 6 ^ 3, 6, 3, 6 ^ 3);
printf("1 << 3 = %d\n", 1 << 3);
printf("16 >> 2 = %d\n", 16 >> 2);
printf("~5 = %d\n", ~5);
Output
6 & 3 = 2 (0110 & 0011 = 0010)
6 | 3 = 7 (0110 | 0011 = 0111)
6 ^ 3 = 5 (0110 ^ 0011 = 0101)
1 << 3 = 8
16 >> 2 = 4
~5 = -6
%04b prints a number in binary, padded to four digits, which shows how each bit combines. ~5 is -6 because integers use two's-complement representation, where inverting all bits of n gives -(n + 1).
Practical Use: Permission Flags
Each permission is assigned a separate bit, so a single integer can store any combination:
<?php
const PERM_READ = 1; // 0001
const PERM_WRITE = 2; // 0010
const PERM_DELETE = 4; // 0100
const PERM_SHARE = 8; // 1000
$permissions = PERM_READ | PERM_WRITE; // grant read and write
var_dump(($permissions & PERM_WRITE) !== 0); // has write?
var_dump(($permissions & PERM_DELETE) !== 0); // has delete?
$permissions |= PERM_DELETE; // add delete
$permissions &= ~PERM_WRITE; // remove write
printf("Permissions: %d (%04b)\n", $permissions, $permissions);
Output
bool(true)
bool(false)
Permissions: 5 (0101)
How It Works
|combines flags:0001 | 0010 = 0011.& FLAGtests a flag: the result is non-zero only if that bit is set. Parentheses are needed because!==has higher precedence than&.|= FLAGturns a bit on.&= ~FLAGturns a bit off:~PERM_WRITEhas every bit set except the write bit.
PHP itself uses this pattern for flags. For example, error_reporting(E_ALL & ~E_DEPRECATED) means "all error types except deprecations", and json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) combines two options.
Note: Bitwise operators on strings operate on the characters' byte values and are rarely what you want. Make sure both operands are integers.
The instanceof Operator
instanceof checks whether an object is an instance of a class, a subclass, or a class implementing an interface.
<?php
$created = new DateTimeImmutable('2026-10-08');
$text = '2026-10-08';
var_dump($created instanceof DateTimeImmutable);
var_dump($created instanceof DateTimeInterface);
var_dump($text instanceof DateTimeInterface);
Output
bool(true)
bool(true)
bool(false)
DateTimeImmutable implements the DateTimeInterface interface, so the second check is also true. A string is not an object, so the last check is false (no error). instanceof is covered in detail in the PHP OOP section.
The Pipe Operator |> (PHP 8.5+)
The pipe operator passes the value on its left as the only argument to the callable on its right. Chained pipes read from left to right, like a sequence of steps.
Without the Pipe Operator
<?php
$title = ' PHP Operators Guide ';
$slug = str_replace(' ', '-', strtolower(trim($title)));
echo $slug;
The functions must be read inside out: trim runs first, but it appears last.
With the Pipe Operator
<?php
$title = ' PHP Operators Guide ';
$slug = $title
|> trim(...)
|> strtolower(...)
|> (fn(string $s): string => str_replace(' ', '-', $s));
echo $slug;
Output (both versions)
php-operators-guide
How It Works
trim(...)is first-class callable syntax: it creates a callable for the function without calling it (see First-class Callable Syntax).- Each step receives the previous result as its single argument.
- When a step needs more than one argument (like
str_replace()), wrap it in an arrow function. In a pipe chain, arrow functions must be enclosed in parentheses.
The pipe operator is only available in PHP 8.5 and newer. On older versions, use nested calls or intermediate variables.
Operators to Avoid
Error Control Operator @
Prefixing an expression with @ suppresses warnings and notices it produces:
<?php
$content = @file_get_contents('/missing/file.txt');
var_dump($content);
Output
bool(false)
The warning about the missing file is hidden, but the problem still exists — $content is false. Hidden errors make bugs very hard to find. Check conditions explicitly instead:
<?php
$path = '/missing/file.txt';
if (!is_readable($path)) {
echo "File not available: $path\n";
} else {
$content = file_get_contents($path);
}
Since PHP 8.0, @ no longer suppresses fatal errors. Use it only in rare, deliberate cases where a failure is expected and fully handled.
Execution Operator (Backticks)
Text inside backticks is executed as a shell command, and its output is returned:
$listing = `ls -la`;
This is equivalent to shell_exec(). Running shell commands is risky — especially with user input, which can lead to command injection — and many hosts disable these functions. Avoid backticks; when a shell command is truly needed, use escapeshellarg() on every argument or a library such as Symfony Process.
Common Mistakes
Confusing = With == or ===
Effect: if ($role = 'admin') assigns 'admin' and is always true.
Fix: Use === for comparison.
Expecting + to Append Arrays
Effect: [1, 2] + [3, 4, 5] gives [1, 2, 5].
Fix: Use array_merge() or [...$a, ...$b].
Testing Bit Flags Without Parentheses
Effect: $perm & PERM_WRITE !== 0 is evaluated as $perm & (PERM_WRITE !== 0).
Fix: ($perm & PERM_WRITE) !== 0.
Relying on Precedence You Are Unsure About
Effect: Expressions mixing ., +, ??, &&, and ?: produce unexpected results.
Fix: Add parentheses.
Suppressing Errors With @
Effect: Failures are silently ignored.
Fix: Check conditions explicitly and handle failures.
Best Practices
- Use
===and!==for comparisons unless you specifically need type conversion. - Add parentheses to any expression where precedence is not immediately obvious.
- Use
$overrides + $defaultsto fill default options, andarray_merge()or spread to combine lists. - Use named constants with bitwise operators for flags, never raw numbers.
- Avoid
@and backticks in application code. - Use the pipe operator (PHP 8.5+) for readable step-by-step transformations when your project's PHP version allows it.
Official reference: https://www.php.net/manual/en/language.operators.php