Let me put my cards on the table: I think True Async's decision to skip colored functions entirely is the single best design call anyone has made for PHP concurrency, and I'd rather see it slip past PHP 8.6 than land with that principle compromised. The project — currently at v0.8.4 and honestly labeled an experimental core — is tracked on php.watch with PHP 8.6 as its target, and the roadmap aims for a stable v1.0 in November 2026, right alongside the 8.6 release scheduled for November 19. Alpha 1 shipped on July 2, Beta 1 is due around mid-August. So the clock is very real. The question I want to argue about isn't whether it makes the train. It's whether we understand what we're signing up for.

First, why the colorless design matters so much for us specifically. In JavaScript or Python, once a function is async, everything that calls it has to become async too, and the split creeps upward through your codebase like damp through a wall. True Async says: no keyword, no annotation, no rewrite. You wrap ordinary code in spawn(), and inside that coroutine, over 70 standard functions — file_get_contents, fread, curl_exec, PDO against MySQL and PostgreSQL, socket_read, even sleep() — quietly become non-blocking. Outside a coroutine they behave exactly as they always have. For a language with twenty-five years of synchronous libraries on Packagist, that's not a convenience feature. It's the only migration path that doesn't require rewriting the ecosystem.

And the engineering underneath is more serious than the usual proof-of-concept. Connection pooling for PDO is built in, so two coroutines don't silently trample the same database handle. flock(), which is a genuinely blocking syscall, gets offloaded to a thread pool so the rest of your coroutines keep moving while one waits on a lock. There's spawn_thread() for actual CPU parallelism, and — this one made me sit up — an HTTP/1.1, HTTP/2 and HTTP/3 server written in C, running inside the PHP process, no reverse proxy in front. Output buffers are isolated per coroutine. Someone thought about the boring failure modes, and in concurrency work the boring failure modes are the whole job.

Now the honest counter-argument, because it's a strong one. Colored functions are annoying, but they're annoying the way a fire alarm is annoying: the async keyword tells you, at the call site, that this line can yield, that the world may have changed underneath you when it returns. True Async's transparency deletes that signal. A static property, a memoized singleton, a Laravel container binding that assumes one request equals one isolated universe — all of that was safe because PHP's shared-nothing model made it safe. Run the same code in cooperative coroutines inside one process and those assumptions become race conditions you can't see in the diff, because the diff is three spawn() calls and nothing else. The very thing that makes adoption easy makes the new bug class invisible.

I still land on the colorless side, and here's why: the alternative isn't a safer PHP, it's a forked PHP. We've run that experiment. AMPHP, ReactPHP and Swoole are excellent, and each one built a parallel universe of drivers and clients because the standard library couldn't cooperate. A colored core would have blessed that segmentation forever — an async PDO and a sync PDO, an async Guzzle and a sync one, duplicated maintenance all the way down. Transparency at the engine level, where the Zend core, the I/O layer and the socket layer are modified directly, is the only version of this where the ecosystem converges instead of splitting. The concurrency bugs are a real price. Library apartheid is a bigger one.

What that means practically: the burden shifts from syntax to discipline, and to tooling. The Scope mechanism — structured concurrency where a group of coroutines lives and dies together, with cancellation designed to not leave data half-written — is where I'd point every framework author right now, because scopes are how you make lifetimes visible again after the keywords are gone. The true-async/ide-helper package (a --dev Composer install) already gives PhpStorm, PHPStan and Psalm proper stubs for spawn() and await(), and I suspect static analysis will end up doing the job the async keyword does elsewhere: flagging shared mutable state that crosses a suspension point. If you want to poke at any of this yourself, the extension installs on PHP 8.5+ via their installer or a Docker image — experimental, not for production, but very much runnable.

So, will it land in 8.6? Nobody can promise that, and I'd genuinely rather wait a cycle than get a rushed core API we're stuck supporting for a decade — the gaps that remain, like directory operations and the Oracle and SQLite PDO drivers, are the small kind, but core APIs are forever. My question to you is the one I keep turning over: when your framework's request lifecycle starts running as coroutines in a single process, what's the first assumption in your own codebase that breaks? I have a shortlist for mine, and none of the entries are flattering. Tell me yours.