0

PHP 8.4 — Deprecated implicit nullable parameters

Intermediate5 min read·php-09-025

Concept

PHP 8.4 deprecated implicit nullable parameters — a longstanding PHP quirk where giving a typed parameter a default value of null implicitly made the type nullable without explicitly declaring ?Type or Type|null.

The behavior: Before PHP 8.4, function foo(string $s = null) was equivalent to function foo(?string $s = null). PHP silently made string nullable because the default was null. This was convenient but inconsistent with PHP's explicit type system.

PHP 8.4 change: This implicit behavior generates E_DEPRECATED. In a future version it will become a fatal error. Code must be updated to explicitly declare ?Type or Type|null.

Migration: Find all function/method signatures with a typed parameter whose default is null but the type isn't nullable. The fix is to add ? prefix: string $s = null?string $s = null. Or, use string|null $s = null if you prefer the union syntax.

Static analysis tools: PHPStan (level 5+) and Psalm already flagged implicit nullable as suspicious before PHP 8.4. Rector (the PHP upgrade automation tool) has a rule to auto-fix this across an entire codebase.

Code Example

php
<?php
declare(strict_types=1);

// DEPRECATED in PHP 8.4 — implicit nullable
function createUser_deprecated(string $name, string $email = null): array // E_DEPRECATED!
{
    return ['name' => $name, 'email' => $email];
}

// CORRECT — explicit nullable
function createUser(string $name, ?string $email = null): array
{
    return ['name' => $name, 'email' => $email];
}

// Also correct — union type syntax
function createUser2(string $name, string|null $email = null): array
{
    return ['name' => $name, 'email' => $email];
}

// Class methods — same rule applies
class UserRepository
{
    // DEPRECATED
    // public function findByEmail(string $email = null): ?array {}

    // CORRECT
    public function findByEmail(?string $email = null): ?array
    {
        if ($email === null) return null;
        return ['email' => $email];
    }
}

// Finding occurrences to fix — grep pattern:
// grep -rn ': [A-Z][a-zA-Z]* $[a-z]* = null' src/
// Or use PHPStan/Psalm to detect deprecated nullable parameters

// Rector auto-fix rule: AddArg\ImplicitNullableParamRector
// composer require rector/rector --dev
// ./vendor/bin/rector process src --rule=Rector\Php84\AddArg\ImplicitNullableParamRector

// Affected contexts: all function/method declarations
// NOT affected: return types (they were always explicit)