Overriding Shared Services in Phalcon's DI Container
Override a shared Phalcon DI service before first use to switch configuration without duplicating bootstrap code.
11 Aug 2025, 18:34 UTC

The Problem: A Shared Service That Needs a Different Value Later
You register a shared service in Phalcon's DI container during bootstrap—for example, a database adapter or a logger configured from environment variables. Later in the same request, a CLI task, or a test bootstrap, you need the same service name to resolve to a different instance or configuration. If you only know how to register services once, you end up duplicating container setup or editing bootstrap code for every environment.
Phalcon\Di\Di is the dependency-injection container shipped with the Phalcon C extension. It stores service definitions and instantiates them lazily, meaning it does not create the object until the first time something asks for it. A shared service registered with setShared returns the same instance on every get call within the container lifecycle.
Registering a Shared Service with Parameters
Use a closure so the container does not connect until the service is first requested. Pass connection details as constructor parameters inside the closure.
// Run inside your PHP application bootstrap (e.g., public/index.php or a CLI task entry point).
// Required: the phalcon C extension must be installed and enabled in PHP.
use Phalcon\Di\FactoryDefault;
use Phalcon\Db\Adapter\Pdo\Mysql;
$di = new FactoryDefault();
$di->setShared('db', function () {
return new Mysql([
'host' => 'primary.db.example.com',
'username' => 'app_user',
'password' => 'change_me',
'dbname' => 'production_db',
]);
});
// The connection is not opened until this line runs.
$primary = $di->get('db');
Where to run and what to check
- Run
php -m | grep phalconin your terminal before executing the script. The output should listphalcon. If it does not, install and enable the extension first. - Run the script with the same PHP user that serves your web requests so file and network permissions match production.
- Check that
$primaryis an instance ofMysqland that$primary === $di->get('db')is true.
Overriding a Service Definition
To point the same service name at a different configuration, register it again before anything resolves the old instance. Phalcon replaces the stored definition for that name.
// Continue in the same bootstrap or task script, before resolving 'db' for the replica.
$di->setShared('db', function () {
return new Mysql([
'host' => 'replica.db.example.com',
'username' => 'app_user',
'password' => 'change_me',
'dbname' => 'production_db',
]);
});
$replica = $di->get('db');
This works cleanly only if the original shared instance has not been resolved yet. Once get('db') returns an object, Phalcon keeps that object for the container lifecycle. Calling setShared again updates the definition, but code that already holds the old object still uses the old connection.
Trade-off and Limitation
Overriding shared services is convenient for environment-specific wiring, but it obscures which instance is active. If two parts of the application expect different configurations under the same service name, the order of registration and resolution determines behavior, which is hard to trace in large bootstrap files.
A safer alternative for tests is to create a separate container instance or use explicit constructor injection instead of reaching into the container from inside classes. Passing the whole $di into controllers turns it into a service locator and hides dependencies.
Verification
There is no rollback step because registering a service only changes in-memory container state; it does not write to a database or alter configuration files.
To verify the override, resolve the service twice after the second registration and compare identity:
$first = $di->get('db');
$second = $di->get('db');
var_dump($first === $second); // expect bool(true)
If the result is not true, the service is not shared or the original instance was resolved before the override.
Closing
Phalcon's DI container lets you register shared, lazily instantiated services and override their definitions before first use. Use this for environment-specific configuration, but keep overrides early and visible in bootstrap. When in doubt, check the documentation for your installed Phalcon version, because DI method names and behavior can differ between major releases.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.