Software Design Enthusiast And Engineer

Aether: A Modern PHP Framework. My Answer To The Age of AI

July 2025

PHP has always been the underdog that wins. From a simple templating tool to powering 80% of the web, it's survived every "PHP is dead" prediction by doing one thing exceptionally well: evolving to meet real needs.

The async revolution in PHP began years ago with brilliant libraries like ReactPHP and AmPHP. These pioneers proved that PHP could handle concurrent I/O, build event-driven architectures, and scale beyond traditional request-response cycles. They laid the groundwork, showed us what was possible.

But somewhere along the way, we hit a wall. Not a technical one - PHP 8.4 shattered those with fibers, property hooks, and lazy proxies. The wall was conceptual: async PHP still felt like writing in a different language, with different rules, different complexity.

Standing on the Shoulders of Giants

I've spent countless hours studying these async libraries, marveling at their ingenuity. ReactPHP's elegant event loop. AmPHP's powerful futures and async iterators. Swoole's raw performance. Each pushed PHP forward in crucial ways.

But I kept wondering: What if we could go further? What if async wasn't a special mode but the default? What if we could steal the best ideas from Rust, .NET, Erlang, and functional programming to create something genuinely new?

Enter Aether

Aether is my love letter to PHP's future, built on foundations that giants created. It takes inspiration from my ventures into other languages and frameworks I deeply admire:

  • From Rust: Monadic Result<T,E> types and ErrorReport for errors (based on the fantastic work in the error_stack crate) that tell complete stories
  • From .NET: Pure dependency injection where containers manage scopes and lifecycles invisibly
  • From Functional Programming: Tasks as impure functions, a.k.a. "Actions" - isolated units of work that compose beautifully
  • From Erlang/OTP: Hierarchical resource management where parent tasks automatically clean up their children
  • From Revolt/AmPHP: Fibers and event-driven concurrency that make all of this possible

The magic happens when these ideas merge with PHP's pragmatism.

Object-Oriented and Functional: Dancing Together

What struck me most in this journey wasn't choosing between paradigms, but discovering how beautifully object-oriented and functional programming dance together in modern PHP.

The OO side provides what we've always loved - self-documentation through class names, rich context through object state, and dependency injection that makes our code testable and maintainable. Meanwhile, the functional side brings data transformations that read like poetry, monadic contracts that make error handling elegant, and that crucial 'unit of work' functionality that makes complex operations composable.

In Aether, a Task is fundamentally a class (OO) that acts as a pure function with side effects (FP). The #[Inject] attributes give us clean dependency management (OO), while the Result<T,E> return types and method chaining give us composable transformations (FP). It's not about picking sides - it's about using each paradigm where it shines brightest.

The AI Application Reality Check

So you're building an AI-powered application. You need to:

  • Gather context from a multitude of sources
  • Process streaming responses from one or many LLM providers
  • Coordinate real-time updates across micro-services
  • Manage the memory that embedded vectors require
  • Do all this without your server catching fire

In most PHP frameworks today, this ranges from "painful" to "impossible." In Aether?

class AIOrchestrationTask extends Task
{
    // These are lazy proxies - created only when first accessed
    #[Inject]
    private LLMPoolInterface $llmPool;
    
    #[Inject]
    private WebSocketBroadcaster $broadcaster;
    
    #[Inject]
    private VectorStore $vectors;
    
    public function __invoke(): Result
    {
        // Each parallel task gets its own fiber, all resources tracked
        return $this->parallel([
            $this->streamFromLLM(...),
            $this->searchSimilarVectors(...),
            $this->coordinateMicroservices(...),
        ])
        ->flatMap($this->mergeAIResponses(...))
        ->flatMap($this->broadcastToClients(...))
        ->tap($this->logMetrics(...));
        
        // When this returns, Aether guarantees:
        // - All WebSocket connections closed
        // - All LLM streams terminated
        // - All database cursors released
        // - Even if exceptions occurred!
    }
    
    private function streamFromLLM(string $prompt): Result
    {
        return $this->llmPool
            ->stream($prompt)  // Returns Result<Stream, ErrorReport>
            ->map($this->processTokens(...))
            ->orMap($this->handleLLMFailure(...));
    }
}

The magic? PHP 8.4's lazy proxies mean dependencies are only created when one of their methods gets called.

The framework tracks resources through these proxies, and combines it with a monadic Result chain.

'monadic' sound intimidating? Just think of it as a cardboard box with an 'ok' or 'err' label on it. Plain and simple.

Real-Time Coordination Made Simple

Here's a real-time collaborative document editor. You know, the kind that usually requires a Node.js backend:

class CollaborativeDocumentTask extends Task
{
    #[Inject]
    private WebSocketPoolInterface $wsPool;
    
    #[Inject]
    private DocumentStore $documents;
    
    #[Inject]
    private ConflictResolver $resolver;
    
    public function __invoke(): Result
    {
        return $this->documents
            ->watch($this->documentId)
            ->flatMap($this->handleDocumentChange(...))
            ->flatMap($this->broadcastToCollaborators(...))
            ->recover($this->handleConflictResolution(...));
    }
    
    private function handleDocumentChange(DocumentEvent $event): Result
    {
        return $this->parallel([
            $this->applyOperationalTransform(...),
            $this->updateCursorPositions(...),
            $this->saveToDatabase(...),
        ])->map($this->consolidateChanges(...));
    }
}

Microservices Without the Pain

Building micro-services in PHP today feels like performing surgery with a butter knife. In Aether:

class OrderProcessingService extends Task
{
    #[Inject]
    private ServiceRegistry $services;
    
    #[Inject]
    private CircuitBreaker $breaker;
    
    public function __invoke(): Result
    {
        // Coordinate multiple services with automatic circuit breaking
        return $this->validateOrder($this->order)
            ->flatMap($this->checkInventory(...))
            ->flatMap($this->processPayment(...))
            ->flatMap($this->scheduleShipping(...))
            ->mapErr($this->handleServiceFailure(...))
            ->tap($this->publishEvents(...));
    }
    
    private function checkInventory(Order $order): Result
    {
        return $this->breaker->call(
            'inventory-service',
            fn() => $this->services
                ->discover('inventory')
                ->flatMap(fn($service) => $service->checkStock($order->items))
        );
    }
}

Breaking Down the Barriers

The async PHP ecosystem reminds me of Linux in the 90s. Powerful? Absolutely. Accessible? Not so much. You needed to be a wizard to make it work, and most people just... didn't.

The barriers aren't technical anymore. PHP 8.4+ has given us everything we need:

  • Fibers for cooperative multitasking without callback hell
  • Lazy Proxies for just-in-time resource creation
  • Property hooks for reactive state management
  • First-class callables for elegant composition
  • Revolt Loop for efficient concurrency

What's missing is a framework that makes these features invisible infrastructure rather than advanced techniques.

What's Really Happening Under the Hood

Here's the beauty of Aether - complexity that serves you, not enslaves you:

class ResourceLifecycleExample extends Task
{
    #[Inject]
    private DatabasePool $db;  // Lazy proxy - not created yet!
    
    public function __invoke(): Result
    {
        // The moment we access $this->db->transaction(...), 
        // PHP 8.4 lazy proxies kick in:
        // 1. Container creates the pool (once per request)
        // 2. Pool registers with Aether's resource tracker
        // 3. Resource gets bound to this task's lifecycle
        
        return $this->db->transaction(function($conn) {
            // Even this inner transaction is tracked!
            return $this->processData($conn);
        });
        
        // When we return (success OR failure):
        // 1. Transaction commits or rolls back
        // 2. Connection returns to pool
    }
}

The secret sauce? Every resource in Aether is wrapped in a lifecycle-aware proxy. Think of it like Rust's RAII or .NET's using statements, but automatic and invisible.

The Power of Modern PHP Syntax

Look how first-class callables and modern PHP features make complex flows readable:

class DataPipelineTask extends Task
{
    #[Inject]
    private DataSourcePool $sources;
    
    #[Inject]
    private MLPipeline $ml;
    
    public function __invoke(): Result
    {
        // PHP first-class callables = beautiful
        return $this->sources
            ->stream('sensor-data')
            ->map($this->parseRawData(...))
            ->filter($this->isValidReading(...))
            ->window(1000) // Process in chunks
            ->flatMap($this->enrichWithML(...))
            ->reduce($this->aggregateResults(...), new Results())
            ->flatMap($this->persistAndNotify(...));
            
        // 8.5's |> operator will be a welcomed addition :)
    }
    
    private function enrichWithML(array $batch): Result
    {
        // Parallel ML inference with automatic resource management
        return $this->parallel(
            array_map(
                fn($data) => fn() => $this->ml->infer($data),
                $batch
            )
        )->map($this->consolidatePredictions(...));
    }
}

Memory-Safe Async That Scales

Here's something that would make most PHP developers nervous - processing gigabytes of data concurrently:

class LargeDataProcessingTask extends Task
{
    #[Inject]
    private StoragePool $storage;
    
    #[Inject]
    private ProcessorPool $processors;
    
    public function __invoke(): Result
    {
        // Process 10GB file without loading it all into memory
        return $this->storage
            ->openStream($this->filePath)
            ->chunks(Bytes::MB(10))
            ->flatMap($this->processChunksConcurrently(...))
            ->tap($this->reportProgress(...))
            ->reduce($this->mergeResults(...), new ProcessingResult());
    }
    
    private function processChunksConcurrently(array $chunks): Result
    {
        // Fan out to multiple processors, automatic cleanup on completion
        return $this->parallel(
            array_map(
                fn($chunk) => fn() => $this->processors
                    ->acquire()
                    ->flatMap(fn($processor) => $processor->process($chunk)),
                $chunks
            )
        );
    }
}

Zero memory leaks. Automatic resource cleanup. Scales to your hardware limits.

Why This Is Our Moment

The AI revolution isn't slowing down. Real-time collaboration is table stakes. Micro-services aren't going away. And you know what? PHP developers shouldn't be sitting on the sidelines watching other languages have all the fun.

We built the modern web with PHP. WordPress, Laravel, Symfony - these aren't just frameworks, they're ecosystems that power millions of businesses. But somewhere along the way, we accepted that PHP was for "traditional" web apps while the cool kids used other tools for "modern" applications.

Screw that.

The Aether Philosophy

This isn't just technical gymnastics. It's a fundamental rethinking of how we build PHP applications:

  1. Async should be invisible, not exceptional
    Every I/O operation in Aether is async by default. But you write it like sync code. The complexity disappears into the framework.

  2. Errors should tell stories with context, not stack traces
    Rust taught us that errors are values. Aether's ErrorReport captures not just what failed, but why, when, and what you can do about it.

  3. Resources should manage themselves
    Inspired by Erlang's "supervision trees", Aether cleans up automatically. Always.

  4. Dependencies should be pure
    No constructor pollution. No service locators. No static properties. Just clean #[Inject] attributes that the container manages.

  5. Tasks should compose like functions
    Each task is an isolated unit of work. They compose, they're testable, they're understandable. Complexity emerges from simplicity.

A Genuinely Fresh Take

This is about fundamentally rethinking what a PHP framework can be in 2025.

// This is Aether in 2025
class ModernPHPApplication extends Task
{
    public function __invoke(): Result
    {
        return $this->bootstrap()
            ->flatMap($this->startServices(...))
            ->flatMap($this->handleRequests(...))
            ->recover($this->gracefulShutdown(...));
    }
    
    // No globals. No statics. No leaks. No fear.
}

Remember when Taylor Otwell showed us that PHP could be expressive and joyful with Laravel? When Jordi Boggiano proved PHP could have modern dependency management with Composer? When Nikita Popov gave us the technical foundations that made PHP 7 revolutionary?

These were paradigm shifts. They changed how we thought about PHP development.

Aether aims to be the next shift. To prove that PHP can be:

  • As concurrent as Go (but more approachable)
  • As diligent as Rust (but more pragmatic)
  • As real-time as Node.js (but more stable)
  • As durable as Erlang (but more familiar)
  • As simple as... well, PHP (because that's our superpower)

The Road to August 2025

I'm not building Aether in secret. This is an open experiment, a bet on PHP's future that I'll be sharing with the world shortly.

I've been putting it to the test and plan to initially release it as an framework for quickly building AI tooling with.

Care to chat? Email me at jonathan.e.havens@gmail.com.


I'm a programmer in Las Vegas who apparently can't leave well enough alone. When not hacking on PHP, I'm probably deep in a Rust book or explaining to someone why PHP 8.4's lazy/ghost objects are actually revolutionary.