Skip to main content

PHP 8.4 TypeError and ArgumentCountError Playbook: What Breaks and How to Fix It

· 5 min read
Victor Jimenez
Software Engineer & AI Agent Builder

PHP 8.4 introduces stricter type and error handling, converting many E_WARNING messages into hard-throwing TypeError and ArgumentCountError exceptions. I built this playbook for identifying potential issues and mitigating them before upgrading.

The problem: more exceptions, less warning

Historically, PHP has been lenient with type mismatches and incorrect argument counts for internal functions, often resulting in warnings, notices, or silent buggy behavior. With PHP 8.4, the engine throws hard exceptions instead.

Breaking Behavior

Code that "works with warnings" in PHP 8.3 can fatally crash in PHP 8.4. A count(null) that returned 0 with a warning now throws a TypeError.

The error handling shift

The solution: a proactive mitigation strategy

Phase 1: static analysis

Terminal
# For PHPStan
vendor/bin/phpstan analyse src/ --level=max

# For Psalm
vendor/bin/psalm --level=1

Pay close attention to errors related to:

  • Invalid types passed to core functions
  • Incorrect argument counts
  • Usage of arithmetic operators on non-numeric types

Phase 2: targeted code review

Change DescriptionBefore (PHP < 8.4)After (PHP 8.4)Mitigation
count() on invalid typesE_WARNINGTypeErrorUse is_countable() before calling count()
Arithmetic/Bitwise on arrays/objectsE_WARNINGTypeErrorEnsure operands are numeric or cast explicitly
Illegal string offsetE_WARNINGTypeErrorValidate array keys before access; use array_key_exists()
exit()/die() with invalid typeInconsistentTypeErrorOnly pass string or int arguments
Magic method type checksNo strict checkTypeError if declared types mismatchAdd or correct type hints for magic methods

Phase 3: fix the code

count() on a non-countable variable:

- $value = null;
- $count = count($value); // Returns 0 with warning
+ $value = null;
+ $count = is_countable($value) ? count($value) : 0;

Arithmetic on an array:

- $items = [1, 2];
- $new_items = $items + 1; // null with warning
+ $items = [1, 2];
+ $items[] = 1; // Append element instead

Full code examples

Before: generates warning in PHP 8.3
// count() on null -- returns 0 with E_WARNING
$value = null;
$count = count($value);
After: safe for PHP 8.4
$value = null;
if (is_countable($value)) {
$count = count($value);
} else {
$count = 0;
}
Before: arithmetic on array
// Array + int -- E_WARNING, result is null
$items = [1, 2];
$new_items = $items + 1;
After: fix the intent
// If you meant to add an element, use array_push or []
$items = [1, 2];
$items[] = 1;

PHP version compatibility matrix

BehaviorPHP 8.1PHP 8.2PHP 8.3PHP 8.4
count(null)Warning + 0Warning + 0Warning + 0TypeError
Array arithmeticWarningWarningWarningTypeError
Illegal string offsetWarningWarningWarningTypeError
Wrong arg count (built-in)ArgumentCountErrorArgumentCountErrorArgumentCountErrorArgumentCountError
Implicit nullable paramsWorksWorksWorksDeprecated
exit() with invalid typeInconsistentInconsistentInconsistentTypeError
Gradual Upgrade Path

A gradual upgrade through minor versions (8.1, 8.2, 8.3) first can make the final jump to 8.4 much smoother by addressing deprecations and changes incrementally.

Migration checklist

  • Run PHPStan at --level=max on all custom code
  • Run Psalm at --level=1 on all custom code
  • Search for count() calls on potentially null/non-countable variables
  • Audit arithmetic operations for non-numeric operands
  • Review magic method type declarations
  • Check all exit()/die() calls for valid argument types
  • Run full test suite on PHP 8.4 in CI
  • Fix all TypeError and ArgumentCountError findings before production deploy
Quick grep patterns to find risky code
# Find count() on variables that might be null
grep -rn 'count(\$' src/ | head -20

# Find arithmetic on array variables
grep -rn '\$.*\[\].*[+\-\*\/]' src/ | head -20

# Find exit/die with variables
grep -rn 'exit(\$\|die(\$' src/ | head -20

Why this matters for Drupal and WordPress

Drupal 12 will require PHP 8.4 as its minimum, and WordPress is actively testing PHP 8.4 compatibility. Both ecosystems have large codebases of contrib modules and plugins that use count() on potentially null values, arithmetic on mixed types, and loose argument counts to internal functions. Drupal sites should run PHPStan against custom modules and contributed code before upgrading. WordPress plugin developers should add PHP 8.4 to their CI test matrix now -- the count(null) TypeError alone will crash plugins that pass unvalidated query results to count functions.

What I learned

  • Proactive static analysis is non-negotiable. Running tools like PHPStan and Psalm at their strictest levels is the most effective first line of defense.
  • The is_countable() function is your new best friend. Its usage should become standard practice before calling count() on any variable whose type is not guaranteed.
  • PHP is continuing its journey toward stricter typing. These changes are not isolated; they are part of a larger trend. Embracing explicit typing now will save headaches later.
  • Do not just suppress errors, understand the intent. When you find code that triggers these new exceptions, the goal is to understand the original developer's intent and fix the underlying logical flaw.

References


Looking for an Architect who doesn't just write code, but builds the AI systems that multiply your team's output? View my enterprise CMS case studies at victorjimenezdev.github.io or connect with me on LinkedIn.