PHP 8.4 — Deprecated implicit nullable parameters
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
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)