Nullable Typed Properties: The PHP Gotcha That Bites During API Deserialization

📖 2 minutes read

Here’s a PHP gotcha that’s bitten me more than once when working with typed properties and external data sources like API responses or deserialized objects.

In PHP 7.4+, when you declare a typed property like this:

class ApiResponse
{
    public ResponseData $data;
}

You might assume that $data defaults to null if it’s never assigned. It doesn’t. It’s in an uninitialized state — which is different from null. Try to access it and you’ll get:

TypeError: Typed property ApiResponse::$data must not be accessed before initialization

This is especially common when deserializing API responses. If the external service returns a malformed payload missing expected fields, your deserializer creates the object but never sets the property. PHP then explodes when you try to read it.

The fix is straightforward — make the property nullable and give it a default:

class ApiResponse
{
    public ?ResponseData $data = null;
}

Two things changed: the ? prefix makes the type nullable, and = null provides an explicit default. Both are required — even a ?Type property without = null stays uninitialized.

Then add a null-safe check where you access it:

if (!$response->data?->items) {
    // Handle missing data gracefully
    return [];
}

The ?-> operator (PHP 8.0+) short-circuits to null instead of throwing an error. Clean and defensive.

The takeaway: Any typed property that might not get initialized — especially in DTOs, API response objects, or anything populated by external data — should be nullable with an explicit = null default. Don’t assume your data sources will always send complete payloads.

Daryle De Silva

VP of Technology

11+ years building and scaling web applications. Writing about what I learn in the trenches.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *