7 PHP Operators That Will Change the Way You Write Laravel Code
Level up your code with modern, high‑impact syntax
Like many Laravel developers, I used to wrestle with walls of if statements and endless conditionals that made my code feel heavier than it should be. Then I discovered a handful of PHP operators that felt like secret weapons. Suddenly, my code was leaner, more readable, and — dare I say — fun to write again. Here are seven operators that can do the same for you.
⭐ Null‑Safe Operator (?->)
The null-safe operator (?->) is a feature in PHP 8+ that makes handling nullable values much cleaner. Instead of writing long if conditions or using isset, you can safely "chain" method calls or property access even if something in the chain is null.
🚦 The Problem Without ?->
Suppose you’re working on a Laravel insurance app where a User may or may not have a Policy.
$policyNumber = null;
if ($user->policy) {
if ($user->policy->details) {
$policyNumber = $user->policy->details->number;
}
}This works, but look at the nested if checks 😓 — very verbose.
✅ Using the Null-Safe Operator
With ?->, you can collapse all that:
$policyNumber = $user->policy?->details?->number;If
policyisnull, it immediately stops and returnsnull.If
detailsisnull, it also stops and returnsnull.Otherwise, it gives you the
number.
So $policyNumber will either be the policy number or null without throwing an error.
✨ Best Practice
Use
?->for optional relationships or deeply nested data.Don’t overuse it where you expect data to always exist — in those cases, better to throw an error than silently return
null.Combine it with the null coalescing operator
??to provide defaults:
⭐Null Coalescing Assignment (??=)
Null Coalescing Assignment (??=) in PHP 7.4+ — it’s like a shortcut for setting a default value only when a variable is null or not set.
🚦 The Problem Without ??=
Imagine you want to set a default timezone for users in a Laravel app:
if (!isset($user->timezone)) {
$user->timezone = 'UTC';
}Or, using the null coalescing operator (??):
$user->timezone = $user->timezone ?? 'UTC';That’s already shorter — but it reassigns the variable explicitly.
✅ Using ??=
With ??=, you can make it even cleaner:
$user->timezone ??= 'UTC';This means:
If
$user->timezoneisnullor not set → assign'UTC'.Otherwise, leave it as is.
✨ Best Practice
Use
??=for default values in configs, request handling, or optional variables.Avoid using it where values must always be present — in those cases, validation is better (
$request->validate()in Laravel).Combine it with arrays when filling optional keys:
$options['limit'] ??= 10;
$options['sort'] ??= 'asc';⭐Spread Operator (...)
The spread operator (...) allows you to “unpack” arrays or arguments into a function, array, or constructor.
Think of it as taking a list of items and "spreading" them out one by one.
1️⃣ Function Arguments
Instead of manually passing every array element, you can unpack it:
function sendNotification($user, $message, $type) {
echo "Sending {$type} notification to {$user}: {$message}";
}
$args = ['John', 'Your order is ready!', 'email'];
// Without spread
sendNotification($args[0], $args[1], $args[2]);
// With spread
sendNotification(...$args);2️⃣ Array Merging
Before PHP 7.4, merging arrays required array_merge():
$defaults = ['status' => 'active', 'role' => 'user'];
$overrides = ['role' => 'admin'];
// Old way
$final = array_merge($defaults, $overrides);
// Spread operator
$final = [...$defaults, ...$overrides];✅ Much shorter, and it feels like JavaScript’s spread syntax.
✨ Best Practices
Use it for clean array merging (instead of
array_merge()everywhere).Great for seeding, configs, and middleware stacking in Laravel.
Don’t overuse in deep nested structures — readability can suffer.
⭐Match Expression (match)
🚦 The Problem Without (match)
Suppose you want to determine the order status label in a Laravel e-commerce app:
$status = 'shipped';
switch ($status) {
case 'pending':
$label = 'Order Pending';
break;
case 'shipped':
$label = 'Order Shipped';
break;
case 'delivered':
$label = 'Order Delivered';
break;
default:
$label = 'Unknown Status';
}Problems:
Lots of boilerplate (
break;everywhere).Can accidentally fall through if you forget
break.Verbose compared to modern syntax.
✅ With match
$status = 'shipped';
$label = match ($status) {
'pending' => 'Order Pending',
'shipped' => 'Order Shipped',
'delivered' => 'Order Delivered',
default => 'Unknown Status',
};Why it’s better:
No fallthrough risk — each case is strictly compared (
===).More compact and returns a value directly.
Cleaner, especially for mappings.
✨ Best Practices
Use
matchinstead ofswitchfor value mapping.Great for status codes, enums, role-based UI, and service resolution.
Always handle the
defaultcase (unless you’re 100% sure you’ve covered all).Combine with exceptions in default if unexpected values are a bug.
⭐ Spaceship Operator (<=>)
Spaceship Operator (<=>) is another modern PHP feature that’s small but super useful, especially for comparisons and sorting.
The spaceship operator (<=>) is a combined comparison operator that returns:
-1if the left side is less than the right0if they are equal1if the left side is greater than the right
So instead of writing multiple if/else comparisons, you can do it in one line.
🚦 The Problem Without <=>
Suppose you want to compare two numbers:
$a = 5;
$b = 10;
if ($a < $b) {
$result = -1;
} elseif ($a == $b) {
$result = 0;
} else {
$result = 1;
}That’s too much boilerplate just to compare values.
✅ With <=>
$a = 5;
$b = 10;
$result = $a <=> $b; // -1If
$a = 5and$b = 10, result is-1If
$a = 10and$b = 10, result is0If
$a = 15and$b = 10, result is1
Clean and elegant 👌
1️⃣ Sorting Arrays
Imagine you want to sort products by price:
$products = [
['name' => 'Product A', 'price' => 200],
['name' => 'Product B', 'price' => 100],
['name' => 'Product C', 'price' => 300],
];
// Without spaceship
usort($products, function ($a, $b) {
if ($a['price'] == $b['price']) return 0;
return ($a['price'] < $b['price']) ? -1 : 1;
});
// With spaceship
usort($products, fn($a, $b) => $a['price'] <=> $b['price']);2️⃣ Multi-level Sorting
Sort users first by role, then by name:
$users = [
['name' => 'Alice', 'role' => 'editor'],
['name' => 'Bob', 'role' => 'admin'],
['name' => 'Charlie', 'role' => 'admin'],
];
usort($users, function ($a, $b) {
return [$a['role'], $a['name']] <=> [$b['role'], $b['name']];
});✅ Both comparisons are done in one go.
3️⃣Comparing Dates
$date1 = new DateTime('2024-01-01');
$date2 = new DateTime('2025-01-01');
$result = $date1 <=> $date2; // -1✅ Works with numbers, strings, and objects that implement compareTo.
✨ Best Practices
Use
<=>in sorting callbacks — it reduces clutter dramatically.Great for multi-field sorting (combine values in an array).
Avoid using it for simple boolean checks (e.g.,
$a > $b) — regular operators are more readable.
⭐Null Coalescing (??) vs. Elvis (?:)
Null Coalescing (??) and the Elvis operator (?:) look similar but behave differently. Many devs mix them up, so let’s break it down with clear examples.
⚡ Null Coalescing (??)
Introduced in PHP 7.
Checks if a variable is set and not null.
If it exists and isn’t null → returns the value.
Otherwise → returns the fallback.
Example
$username = $_GET['user'] ?? 'Guest';If
$_GET['user']exists and is not null →$username = $_GET['user'].Otherwise →
$username = 'Guest'.
✅ Safe for undefined variables/array keys (no notice error).
⚡ Elvis Operator (?:)
A shorthand for ternary without the middle part.
Evaluates truthiness (not just null).
If the value is truthy → returns it.
If falsy (null, false, 0,
'',[]) → returns the fallback.
Example
$username = $_GET['user'] ?: 'Guest';If
$_GET['user']is truthy →$username = $_GET['user'].If falsy (
null, empty string,0,false) →$username = 'Guest'.
❗ Difference: Here, even an empty string or 0 will fall back, unlike ??.
🔍 Side-by-Side Difference
Examples-2
1. Null Coalescing (??) for Defaults
$limit = $request->input('limit') ?? 10;If
limitis missing/null → use10.If
limit = 0→ still0(valid).
2. Elvis (?:) for Falsy Checks
$username = $request->input('username') ?: 'Guest';If
username = ""(empty string) → fallback to'Guest'.If
username = "John"→ keep"John".
✨ Best Practice
Use
??when you care about null/undefined only (like request params, config values).Use
?:when you care about any falsy value (like optional form fields).Always think: “Do I want
0or''to be considered valid or not?”
⭐Null Coalescing Nesting & Chaining
🚦 The Problem Multiple fallbacks with nested ternaries get messy.
$value = isset($a) ? $a : (isset($b) ? $b : $c);✅ With
$value = $a ?? $b ?? $c;⚡ Why It Rocks: Chain any number of defaults cleanly — no parentheses or nested calls.
Example
Suppose you want to get a user’s phone number. The phone can come from multiple places:
Profile phone
Contact phone
Fallback:
"Not Provided"
Old Way
$phone = null;
if (isset($user->profile) && isset($user->profile->phone)) {
$phone = $user->profile->phone;
} elseif (isset($user->contact) && isset($user->contact->phone)) {
$phone = $user->contact->phone;
} else {
$phone = 'Not Provided';
}😩 Lots of if/else, very verbose.
✅ With ?? (Clean Way)
$phone = $user->profile?->phone
?? $user->contact?->phone
?? 'Not Provided';First tries
$user->profile->phone.If null, tries
$user->contact->phone.If still null, defaults to
'Not Provided'.
✅ Short, expressive, and safe.
✨ Best Practices
Use nesting (
??) for layered defaults (multi-source input, config).Combine with null-safe operator (
?->) for safe chaining of object/relationship access.Don’t over-nest — if you have more than 2–3 fallbacks, extract into a method for readability.


