Operators
Operators are the symbols that work on values: + adds, === compares, && combines conditions. You have already used a few. PHP has many more, and some of them, like ==, behave in ways that surprise beginners.
In this lesson you will learn the operators you need every day, the difference between == and ===, and the modern shortcuts that make PHP code shorter and safer: ??, ??=, ?-> and the new pipe operator.
Assignment and increment
= stores a value. Combined assignment operators update a variable using its own current value: $x += 5 is short for $x = $x + 5. There is one for each arithmetic operator, plus .= for strings.
++ adds one and -- subtracts one. Written after the variable ($i++) the old value is used first; written before (++$i) the variable changes first. Most code uses them as a statement on their own, where both forms do the same thing.
<?php
declare(strict_types=1);
$wallet = 500;
$wallet += 250;
$wallet -= 120;
$wallet *= 2;
$wickets = 3;
$wickets++;
$log = 'Recharged';
$log .= ', paid bill';
echo $wallet, "\n";
echo $wickets, "\n";
echo $log, "\n";1260 4 Recharged, paid bill
Comparison: == and ===
Comparison operators return true or false:
| Operator | True when |
|---|---|
$a == $b | Equal after type juggling |
$a === $b | Equal and the same type |
$a != $b | Not equal after type juggling |
$a !== $b | Not equal, or not the same type |
<, >, <=, >= | Less than, greater than, and so on |
The double equals == is called loose comparison. It converts types before comparing, which gives some strange results. The triple equals === is strict: values of different types are never equal.
<?php
declare(strict_types=1);
var_dump('18' == 18);
var_dump('18' === 18);
var_dump('1' == '01');
var_dump('10' == '1e1');
var_dump(null == false);
var_dump('abc' == 0);bool(true) bool(false) bool(true) bool(true) bool(true) bool(false)
Look at '10' == '1e1'. Both strings look like numbers (1e1 is scientific notation for 10), so == compares them as numbers. With ===, they are just two different strings. PHP 8 fixed the worst old surprise: 'abc' == 0 used to be true and is now false.
The rule is simple: use === and !== by default. Use == only when you have thought about type juggling and really want it.
The spaceship operator
<=> compares two values and returns -1 if the left is smaller, 0 if they are equal and 1 if the left is bigger. It looks like a little spaceship, hence the name. Its main use is sorting, which you will see in Array Functions. For example, 5 <=> 9 is -1 and 'b' <=> 'a' is 1.
Logical operators
Logical operators combine conditions:
| Operator | Meaning | True when |
|---|---|---|
$a && $b | And | Both are true |
$a || $b | Or | At least one is true |
!$a | Not | $a is false |
$a xor $b | Exclusive or | Exactly one is true |
PHP stops checking as soon as it knows the answer. In $a && $b, if $a is false, $b is never evaluated. This is called short-circuit evaluation.
<?php
declare(strict_types=1);
$age = 19;
$hasVoterId = true;
$isHoliday = false;
$canVote = $age >= 18 && $hasVoterId;
$canSleepIn = $isHoliday || $age < 5;
var_dump($canVote);
var_dump($canSleepIn);
var_dump(!$canVote);bool(true) bool(false) bool(false)
Ternary, ?? and ??=
The ternary operator condition ? valueIfTrue : valueIfFalse picks one of two values. It is handy for short choices. For anything longer, use an if statement.
The null coalescing operator ?? returns the left value if it exists and is not null, otherwise the right value. It never shows an "undefined" warning, which makes it perfect for optional data such as form fields. The null coalescing assignment ??= sets a variable only if it is currently null or missing.
<?php
declare(strict_types=1);
$marks = 72;
$result = $marks >= 33 ? 'Pass' : 'Fail';
echo $result, "\n";
$form = ['name' => 'Ananya', 'city' => 'Kochi'];
echo $form['city'] ?? 'Not given', "\n";
echo $form['phone'] ?? 'Not given', "\n";
$settings = [];
$settings['theme'] ??= 'light';
$settings['theme'] ??= 'dark';
echo $settings['theme'], "\n";Pass Kochi Not given light
The second ??= does nothing because theme already has a value.
You may also see the short ternary $a ?: $b, which returns $a if it is truthy. Be careful: '0' ?: 'Guest' gives 'Guest', because '0' is falsy. Use ?? when you only want to replace missing or null values.
The nullsafe operator ?->
The arrow -> reads a property or calls a method on an object (you will learn objects in Classes & Objects). If the object is actually null, PHP shows a warning. The nullsafe operator ?-> stops and returns null instead:
<?php
declare(strict_types=1);
class Address
{
public string $city = 'Jaipur';
}
class Customer
{
public ?Address $address = null;
}
$withAddress = new Customer();
$withAddress->address = new Address();
$noAddress = new Customer();
echo $withAddress->address?->city ?? 'No city', "\n";
echo $noAddress->address?->city ?? 'No city', "\n";Jaipur No city
Without ?->, the last line would show the warning "Attempt to read property "city" on null". Combining ?-> with ?? gives a clean default.
The pipe operator
Precedence
When an expression has several operators, PHP follows precedence rules, just like maths: * before +, comparisons before &&, and && before ||. You do not need to memorise the full table. Add brackets whenever the order is not obvious to a reader: ($price + $delivery) * $quantity.
Common mistakes
- Using
=instead of===in a condition.if ($role = 'admin')assigns'admin'and is always true. - Using
==with user input.'1e1' == '10'istrue. Use===. - Using
and/or. Their low precedence breaks assignments. Use&&and||. - Using
?:when you meant??.?:also replaces0,'0'and'', which may be real values. - Expecting string comparison to ignore case.
'Pune' === 'pune'isfalse, and uppercase letters sort before lowercase ones.
Key points
- Combined assignments like
+=and.=update a variable in place. ===compares value and type; prefer it over the loose==.<=>returns -1, 0 or 1 and is mainly used for sorting.- Use
&&,||and!for logic; avoidandandor. ??gives a default for missing ornullvalues;??=assigns only when missing.?->safely reads through objects that may benull.- PHP 8.5's pipe operator
|>chains one-argument callables from left to right.
Exercise
A movie ticket costs ₹250. Children under 12 and seniors aged 60 or more get a 40% discount. Write a script with $age = 64 and $form = ['name' => 'Kabir']. Use || to decide whether the discount applies, a ternary to choose the price, and ?? to print the seat preference from $form['seat'], defaulting to 'Any'. Print the name, price and seat.
Show solution
<?php
declare(strict_types=1);
$age = 64;
$form = ['name' => 'Kabir'];
$fullPrice = 250;
$discount = $age < 12 || $age >= 60;
$price = $discount ? $fullPrice * 60 / 100 : $fullPrice;
$seat = $form['seat'] ?? 'Any';
echo "{$form['name']}: ₹$price, seat: $seat\n";Kabir: ₹150, seat: Any
$discount is true because the age is 60 or more, so the ternary picks the discounted price. The form has no seat key, so ?? supplies 'Any' without a warning.
Quick Quiz
1. What does '18' === 18 return?
=== also checks the type, and a string is not an int.
2. What is stored in $theme after $theme = null; $theme ??= 'dark'; $theme ??= 'light';?
The first ??= assigns because $theme is null; the second does nothing.
3. What does $user?->email return when $user is null?
The nullsafe operator stops the chain and returns null instead of showing a warning.
4. In PHP 8.5, what does ' hi ' |> trim(...) |> strtoupper(...) produce?
The value is trimmed first and the result is then passed to strtoupper().
Learn PHP with a mentor
Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
