Some calls ask for so much memory that PHP can tell they'll fail before it even starts. str_repeat('x', PHP_INT_MAX) is one example, and array_fill(0, 2 ** 30, 0) is another. Today these end in an uncatchable fatal error that kills the whole request. This RFC from Ben Ramsey adds a MemoryError that PHP throws instead, so your code can catch it, log it and keep going.

How it works

MemoryError is a new class that extends Error. Before a guarded function allocates anything, PHP calculates the size it needs. If that won't fit in what's left of memory_limit, PHP throws.

ini_set('memory_limit', '64M');

try {
    $s = str_repeat('x', PHP_INT_MAX);
} catch (MemoryError $e) {
    // The resulting string is too large to fit in the configured memory limit
    echo $e->getMessage();
}

$s = 'abc';
try {
    $s[2 ** 40] = 'Z';
} catch (MemoryError $e) {
    // $s is still 'abc'
}

Because the check runs before anything is allocated or copied, a failed call leaves your data unchanged.

The guard is added to many functions whose output size depends on an argument, including:

  • String builders like str_repeat(), str_pad(), number_format() and sprintf() widths
  • Array builders like array_fill(), range(), str_split() and new SplFixedArray()
  • Read buffers like random_bytes(), fread(), fgets() and socket_read()

Some things stay the same. With memory_limit = -1, PHP never throws this error. A genuine out-of-memory condition in the middle of work is still a fatal error, because PHP would need memory to throw an exception at that point.

The RFC's benchmarks show the guard adds very little overhead per call, and extensions can use the new C functions for their own checks.

What it means for existing code

  • A class named MemoryError in the global namespace would clash. The RFC's search of public code found none.
  • Cases that used to be fatal errors now throw.
  • mb_str_pad() used to throw Error with "String size overflow" in one rare case. It now throws MemoryError with the new message, which only matters if your code checks the message text.
  • A script that's nearly out of memory may now get a MemoryError even for a small request. That request would have died with a fatal error before.

Where it stands

It's a draft targeting PHP 8.6, with an implementation pull request open. The poll on the page is a placeholder with no votes.