Nullable Types

Ma Mariya Vinciya Updated 21 Oct 2026
5 min read ·Lesson 164 of 174
In this post

What Is a Nullable Type? In simple terms: Sometimes a value may legitimately be absent : a customer without a middle name, an order without a coupon, a search that finds no user. A nullable type says

What Is a Nullable Type?

In simple terms: Sometimes a value may legitimately be absent: a customer without a middle name, an order without a coupon, a search that finds no user. A nullable type says "this is a string — or nothing (null)". It makes the possibility of "no value" explicit in the code, so both PHP and other developers know they must handle it.

Technically: A nullable type is written with a leading question mark: ?string. It is equivalent to the union type string|null (PHP 8.0+). Nullable types can be used for parameters, return values, and properties. A non-nullable type such as string rejects null with a TypeError.

DeclarationAccepts
string $nameStrings only
?string $nameStrings or null
`stringnull $name`Same as ?string
?string $name = nullStrings or null, and the argument may be omitted

 


Nullable Parameters

<?php
function greet(?string $name): string
{
    return $name === null ? 'Hello, guest!' : "Hello, $name!";
}

echo greet('Asha') . "\n";
echo greet(null) . "\n";

try {
    greet();
} catch (ArgumentCountError $e) {
    echo strstr($e->getMessage(), ' in ', true) . "\n";
}

 

Output

Hello, Asha!
Hello, guest!
Too few arguments to function greet(), 0 passed

 

Nullable Is Not the Same as Optional

  • ?string $name means the argument may be null, but it must still be passed.
  • To make it optional, add a default value: ?string $name = null.
function greet(?string $name = null): string { ... }

greet();          // allowed: $name is null
greet(null);      // allowed
greet('Asha');    // allowed

 


Implicitly Nullable Parameters Are Deprecated (PHP 8.4)

Older code often relied on a special rule: a parameter with a non-nullable type and a default of null was implicitly nullable:

<?php
function oldStyle(string $coupon = null): string
{
    return $coupon ?? 'no coupon';
}

echo oldStyle() . "\n";

 

Output (PHP 8.4+)

PHP Deprecated:  oldStyle(): Implicitly marking parameter $coupon as nullable is deprecated, the explicit nullable type must be used instead in /path/script.php on line 2
no coupon

 

The declaration string $coupon claims the parameter is always a string, while = null silently contradicts that. Since PHP 8.4, write the nullability explicitly:

function newStyle(?string $coupon = null): string

 

Tools such as PHP-CS-Fixer and Rector can fix this automatically in existing code bases.


Nullable Return Types

A nullable return type tells callers that a function may return "nothing" — typically for lookups:

<?php
final class Address
{
    public function __construct(public string $city) {}
}

final class User
{
    public function __construct(
        public readonly int $id,
        public readonly string $name,
        public readonly ?Address $address = null,
    ) {}
}

function findUser(int $id): ?User
{
    $users = [
        7 => new User(7, 'Asha', new Address('Chennai')),
        8 => new User(8, 'Bala'),
    ];

    return $users[$id] ?? null;
}

foreach ([7, 8, 9] as $id) {
    $user = findUser($id);

    $name = $user?->name ?? 'Unknown user';
    $city = $user?->address?->city ?? 'city not set';

    echo "#$id: $name, $city\n";
}

 

Output

#7: Asha, Chennai
#8: Bala, city not set
#9: Unknown user, city not set

 

How It Works

  1. findUser() returns a User or null when no user exists — the ?User return type documents this.
  2. The nullsafe operator ?-> (see Nullsafe Operator) stops the chain and returns null when the value on its left is null, instead of throwing an error.
  3. The null coalescing operator ?? supplies a fallback for null results.
  4. Address is also nullable on User: Bala has no address, so $user?->address?->city is null.

Nullable Properties

<?php
final class Customer
{
    public ?string $nickname = null;   // initialized with null
    public ?string $referralCode;      // uninitialized
}

$customer = new Customer();

var_dump($customer->nickname);

try {
    var_dump($customer->referralCode);
} catch (Error $e) {
    echo $e->getMessage() . "\n";
}

 

Output

NULL
Typed property Customer::$referralCode must not be accessed before initialization

 

A nullable type allows null, but it does not set null automatically. Without = null, the typed property starts uninitialized (see PHP Properties).


Avoiding Unnecessary Nulls

Every nullable value forces every caller to check for null. Nulls that spread through an application lead to repetitive checks — or to forgotten checks and errors. Use nullable types where "absent" is a genuine, expected state, and consider alternatives elsewhere:

SituationInstead of null
A list with no itemsReturn an empty array []
An operation that must succeedThrow an exception when it fails
"No behavior" (no discount, no logger)A Null Object that does nothing
A value with a sensible defaultUse the default ('INR', 0, '')

 

Example: The Null Object Pattern

<?php
interface Discount
{
    public function apply(float $amount): float;
}

final class PercentageDiscount implements Discount
{
    public function __construct(private float $percent) {}

    public function apply(float $amount): float
    {
        return round($amount * (1 - $this->percent / 100), 2);
    }
}

final class NoDiscount implements Discount
{
    public function apply(float $amount): float
    {
        return $amount;
    }
}

final class Order
{
    public function __construct(
        private float $subtotal,
        private Discount $discount = new NoDiscount(),
    ) {}

    public function total(): float
    {
        return $this->discount->apply($this->subtotal);   // no null check needed
    }
}

echo (new Order(1000))->total() . "\n";
echo (new Order(1000, new PercentageDiscount(10)))->total() . "\n";

 

Output

1000
900

 

Instead of a ?Discount property and if ($this->discount !== null) checks, an order always has a discount — sometimes one that changes nothing. (new in a parameter default requires PHP 8.1+.)


Common Mistakes

Confusing Nullable With Optional

Effect: ArgumentCountError when the argument is omitted.

Fix: Add = null if the argument may be left out.

Relying on Implicit Nullability

Effect: Deprecation notices in PHP 8.4.

Fix: Write ?Type $param = null.

Forgetting to Handle null Return Values

Effect: "Attempt to read property on null" warnings or errors.

Fix: Check for null, or use ?-> and ??.

Using null for Empty Collections

Effect: Every caller must check for null before looping.

Fix: Return an empty array.


Best Practices

  • Use nullable types only where "no value" is a legitimate, expected state.
  • Write nullable types explicitly (?Type), never implicitly through = null alone.
  • Handle null immediately with ??, ?->, or explicit checks.
  • Return empty collections instead of null for lists.
  • Consider exceptions or Null Objects instead of nullable returns and properties.

Official reference: https\://www.php.net/manual/en/language.types.declarations.php#language.types.declarations.nullable

0 Comments

Reviewed before they appear

No comments yet.

PHP
PHP Home PHP Switch PHP Match Alternative Syntax PHP Loops While Loop Do While Loop For Loop Foreach Loop Nested Loops Break Statement PHP Intro PHP Install PHP Built-in Web Server PHP Syntax PHP Tags PHP and HTML PHP Comments PHP Multiline Comments PHP Variables Variables Scope PHP Casting Logical Operators Null Coalescing Operator Spaceship Operator Operator Precedence Continue Statement Modify Strings PHP If...Else...Elseif PHP If Modify Strings PHP If Operators PHP Functions Concatenate Strings PHP If...Else User-defined Functions Slicing Strings PHP Shorthand if Escape Characters Default Argument Values PHP Nested if Pass by Reference String Interpolation Named Arguments PHP File Upload Variadic Functions Return Values Search in Strings Multibyte Strings Type Declarations in Functions PHP Numbers PHP Math PHP Floats PHP Random Numbers PHP Constants PHP Properties PHP Methods PHP Constructor Constructor Property Promotion PHP Cookies PHP Destructor PHP Access Modifiers Readonly Properties PHP Sessions PHP Inheritance Method Overriding PHP Filters The final Keyword CSRF Protection PHP Filters Advanced Session Security Secure Cookies PHP Magic Constants File Upload Security PHP Callback Functions PHP Operators Filesystem Security PHP JSON Arithmetic Operators Error Reporting in Production Hiding PHP Assignment Operators PHP Configuration (php.ini) Comparison Operators PHP Command Line (CLI) PHP Exceptions Increment / Decrement Operators Migrating to PHP 8 PHP Form Validation PHP Form Required PHP Form URL/E-mail Error Handling Form Input Sanitizing Escaping Output (htmlspecialchars) Custom Error Handler Checkbox, Radio and Select Inputs Sticky Forms PHP Form Complete PHP Date and Time Date Formatting Error Logging HTTP Headers and Redirects Output Buffering Sending Email PHP cURL Consuming REST APIs PHP Generators AJAX PHP AJAX Database AJAX XML AJAX Live Search AJAX Poll AJAX with JSON Security Introduction Password Hashing SQL Injection Prevention XSS Prevention Garbage Collection Project: Simple Blog PHP What is OOP PHP Classes/Objects The $this Keyword Access Array Items Update Array Items Add Array Items Remove Array Items Sorting Arrays Multidimensional Arrays Array Destructuring Array Spread Operator Search in Arrays Merge Arrays PHP Abstract Classes PHP Interfaces Polymorphism PHP Traits PHP Static Methods PHP Static Properties Late Static Binding Magic Methods Object Cloning MySQL Database MySQL Connect MySQL Create DB MySQL Create Table MySQL Insert Data MySQL Get Last ID MySQL Insert Multiple MySQL Prepared MySQL Select Data MySQL Where Debugging PHP Project: Image Upload Gallery $_SESSION $_ENV PHP RegEx RegEx Patterns Heredoc and Nowdoc RegEx Modifiers preg_match preg_replace preg_split PHP RegEx Functions Nullable Types Mixed and Never Types Nullsafe Operator PHP Attributes PHP Fibers Readonly Classes Property Hooks (PHP 8.4) Asymmetric Visibility (PHP 8.4) Reflection API SPL Data Structures Composer
Ask about this post
AI Ask about this post

Ask questions about Nullable Types and get answers drawn from it.

Signed-in readers only.