Skip to Content
Course content
Click on the "Edit" button in the top corner of the screen to edit your slide content.

I was digging through some legacy code the other day and ran into a classic PHP headache. I had a User object, and I needed to grab the city from the user's address to display it on a shipping label. Seems simple enough, right?

The 'Fatal Error' we've all seen

I started with the most direct approach. I just chained the calls together. Here is exactly what I wrote:

$city = $user->getAddress()->getCity();

Everything worked perfectly during my first few tests. But then, I hit a user profile that didn't have an address on file. Suddenly, the whole page crashed with a Fatal error: Uncaught Error: Call to a member function getCity() on null. This happens because getAddress() returned null, and PHP can't call a method on something that doesn't exist.

Fighting the Verbosity

Now, if I'm writing this for a production environment, I can't just let the site crash. I need to check if the address exists first. This is how we used to handle it (and how a lot of us still do by habit). I'd write something like this:

$address = $user->getAddress();
$city = null;

if ($address !== null) {
    $city = $address->getCity();
}

It works. It's safe. But honestly? It's tedious. If I had to go deeper—say, $user->getAddress()->getCountry()->getIsoCode()—I'd end up with a pyramid of if statements that makes the code hard to read and even harder to maintain. I don't want to spend half my day writing null checks.

Letting PHP handle the nulls

This is where the nullsafe operator (?->) comes in. It's a relatively recent addition to PHP that basically tells the engine: "Try to call this method, but if the thing on the left is null, just stop right there and return null for the whole expression."

Let's rewrite that shipping label line using the nullsafe operator:

$city = $user->getAddress()?->getCity();

I tried this with the "empty" user profile again. Instead of a fatal error, $city simply became null. No crash, no messy if blocks. It just short-circuits.

The real magic happens when you chain several of these together. Check this out:

$isoCode = $user->getAddress()?->getCountry()?->getIsoCode();

In this one line, PHP is checking if the address exists, then checking if the country exists, and only then trying to get the ISO code. If any link in that chain is null, the whole thing gracefully evaluates to null. It's a massive quality-of-life improvement for anyone dealing with deeply nested data objects.

  • Use ?-> when you aren't 100% sure a method or property belongs to an object that actually exists.
  • Remember that the result of the entire chain will be null if any part of it is null.
  • Don't use it everywhere blindly; if a null value indicates a serious problem that should stop the program, a standard crash (or a thrown Exception) is actually more helpful for debugging.



📋 Practical Task

Fixing the Customer Order Shipping Chain

You are working on an e-commerce platform. You have an Order object that might have a ShippingDetails object, which in turn might have a Courier object. You need to retrieve the courier's phone number for the customer support dashboard.

Below is a snippet of code that is currently causing "Call to a member function on null" errors whenever an order is marked for "Digital Delivery" (meaning it has no shipping details).

class Courier {
    public function getPhone() { return "555-0123"; }
}

class ShippingDetails {
    public function getCourier() { return new Courier(); }
}

class Order {
    private $shipping;
    public function __construct($hasShipping) {
        $this->shipping = $hasShipping ? new ShippingDetails() : null;
    }
    public function getShippingDetails() { return $this->shipping; }
}

// TEST CASE: Digital Order (no shipping)
$order = new Order(false);

// FIX THE LINE BELOW:
$phone = $order->getShippingDetails()->getCourier()->getPhone();

echo "Courier Phone: " . ($phone ?? "N/A");

Your Task: Rewrite the line assigning the $phone variable using the nullsafe operator so that the code handles digital orders without throwing a fatal error.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.