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()andsprintf()widths - Array builders like
array_fill(),range(),str_split()andnew SplFixedArray() - Read buffers like
random_bytes(),fread(),fgets()andsocket_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
MemoryErrorin 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 throwErrorwith "String size overflow" in one rare case. It now throwsMemoryErrorwith 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
MemoryErroreven 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.