Because Maravel-Framework resolves most of the Macroable classes from DI, version 10.73.3 and 20.0.0-RC35 make the Mailer and Dispatcher classes resolvable from container even if previously that would have triggered a circular dependency infinite loop.
I let Gemini present the patch:
Slaying the Circular Dependency Dragon: Inside Maravel 10.73.3 and 20.0.0-RC35
When you are building high-performance PHP engines like Maravel (our ultra-fast Lumen alternative) and Maravelith (our monolithic Laravel alternative), the Dependency Injection (DI) Container is the beating heart of the system. It needs to be lightning-fast, predictable, and memory-efficient.
But occasionally, the container trips over its own shoelaces.
In our latest release cycle for Maravel-Framework (versions 10.73.3 and the upcoming 20.0.0-RC35), we tackled one of the most frustrating architectural traps in modern framework design: The Core Alias Boot Loop.
Here is the story of how a sneaky circular dependency crashed our kernel boot sequence, how our custom memory guardrail caught it, and the architectural changes we shipped to fix it for good.
The Trap: The Instantiation Loop
To keep the framework highly extensible, core components are registered in the DI container using short string aliases. The Event Dispatcher is aliased as 'events', and the Mail Manager is aliased as 'mailer'.
But what happens when the very factory responsible for booting the Mailer or the Dispatcher asks the container to resolve its own alias while it is still being built?
You get an Instantiation Loop.
- The framework boots and says: “I need the Mailer.”
- The Container looks up the 'mailer' alias.
- The Alias points to a Service Provider Factory.
- Inside that Factory, the code triggers \di(Mailer::class) to resolve dependencies.
- The container hits the alias redirect, loops back to step 1, and starts over.
Before the object ever exists in memory, the container spins infinitely. Eventually, this violent loop exhausts the PHP worker’s memory, resulting in a fatal memory limit exhausted crash.
The Solution: makeWithoutAlias
To break this chicken-and-egg cycle without sacrificing the flexibility of our alias registry, we introduced a new core method across both the Illuminate\Contracts\Container\Container interface and the concrete implementation: makeWithoutAlias (v10.73.3 does not include it in the Contract for BC reasons).
// The Old Way (Triggers the Alias Trap)
$mailer = \di(Mailer::class, [
$name,
$this->app['view'],
$this->createSymfonyTransport($config),
$this->app['events'],
]);
// The New Way (Safe, Unaliased Factory Resolution)
$mailer = $this->app->makeWithoutAlias(Mailer::class, [
$name,
$this->app['view'],
$this->createSymfonyTransport($config),
$this->app['events'],
]);
// notice the list parameters supported by Maravel-Framework
By using makeWithoutAlias, the container explicitly bypasses the forward/reverse lookup arrays ($this->aliases and $this->abstractAliases). It evaluates the concrete class directly through the reflection and cache pipeline.
This completely isolates the framework’s core boot sequence from the user-land alias registry. The Event Dispatcher and Mail Manager now boot cleanly, perfectly intact, and ready to accept faster child class bindings versus macros.
Bridging to Maravel 20: Dropping Stack Frames
While makeWithoutAlias was backported to 10.73.3 to secure existing production deployments, 20.0.0-RC35 cements it as an immutable architectural baseline.
In the v10 patch line, this fix required an internal bridge method (resolveFinalAbstract) to handle the routing safely without breaking backward compatibility. But in v20.0.0-RC35, we ripped the band-aid off.
We completely removed the final protected function resolveFinalAbstract(). The container resolution layers now route cleanly and directly into resolveFinalString(). By eliminating this redundant method stack frame, the v20 DI container executes with even less overhead.
A Word on “Execution Loops” and Production Guardrails
It is important to note that while makeWithoutAlias perfectly solves the instantiation loop during framework boot, it cannot stop developers from writing execution loops at runtime (e.g., logging an SQL query to the database, which triggers a new QueryExecuted event, which logs a new query, infinitely).
To protect against this, Maravel-Framework includes a native Circular Dependency Memory Monitor. It tracks the recursion depth of resolved classes and measures the memory growth delta.
Pro-Tip for Upgrading Developers: Never set your circular_dependency_memory_limit to 0 in production if your sandbox does not cover all possible scenarios.
Conclusion
Micro-optimizations matter, but structural integrity is paramount. With 10.73.3 and 20.0.0-RC35, we have completely immunized the Maravel core against alias boot loops while making the DI container leaner than ever.
Update your composer.json, leverage makeWithoutAlias in your custom foundational service providers, and enjoy the speed.
Maravel-Framework v10 is actively maintained, while v20.0.0 is slated for final release later this year. Check out the latest release notes and template updates on our [_GitHub](https://github.com/macropay-solutions)._
NOTE
10.x and 20.x documentations have been updated for this change:
- https://macropay-solutions.github.io/maravelith-docs/10.x/container#the-makewithoutalias-method
- https://macropay-solutions.github.io/maravel-docs/20.x/upgrade#3-container--architecture-breaking-changes
- https://macropay-solutions.github.io/maravelith-docs/20.x/upgrade#3-container--architecture-breaking-changes

Top comments (0)