amphp-injector in Flyokai¶
Flyokai-specific DI configuration patterns and conventions built on flyokai/amphp-injector.
For the core amphp-injector API, see vendor/flyokai/amphp-injector/README.md (and the deeper AGENTS.md).
DI Config File Structure¶
Each Flyokai module returns an array from its diconfig*.php:
return [
// Interface → Implementation mappings
'aliases' => [
ConnectionPool::class => AsyncMysqliConnectionPool::class,
AclRoleRepository::class => AclRoleRepositoryImpl::class,
],
// Constructor argument overrides (by parameter name)
'arguments' => [
TwoLevelConnectionPool::class => [
'firstPool' => $service(AsyncMysqliConnectionPool::class),
'secondPool' => $service(AmpConnectionPool::class),
],
ApplicationLogger::class => [
'name' => $rootBootstrap->applicationType->buildName($rootBootstrap->name),
'handlers' => [
'default' => $streamHandlerDefinition
]
],
],
// Non-service definitions (prototypes, shared non-service singletons)
'definitions' => [
ApplicationLogger::class => singleton(object(ApplicationLogger::class)),
Controller\Ping::class => object(Controller\Ping::class),
],
// Runtime attribute-based definitions
'runtimeDefinitions' => [
]
];
Build Flow in Flyokai¶
- Module bootstraps call
addDiConfigFile()during init phase - Each diconfig file returns the array above
RootBootstrapmerges all configs, createsDefinitions+Arguments(from weavers)Applicationis constructed — callsdefinition->build(injector)for every definition, registering providers in Containerapplication->start()walks all providers, startsLifecycleinstances in dependency orderapplication->stop()stops in reverse order
Services vs Definitions¶
addService(id, definition)— registered as a named service in the container, accessible via$container->get(id)addDefinition(id, definition)— registered in definitions collection, used for wiring but not directly retrievable as a service- The
$service(...)and$definition(...)closures (from$rootBootstrap->getDiConfig()) reference previously registered services/definitions for cross-wiring
Config File Scoping¶
Files are loaded per ApplicationType:
- diconfig.php — base, always loaded
- diconfig_web.php — Web and Worker types
- diconfig_cli.php — Cli type
- diconfig_cluster.php — Cluster type
- diconfig_worker.php — Worker type
- diconfig_setup.php — Setup type
Arguments Merging¶
Arguments from the 'arguments' key in diconfig are merged into existing definitions by matching class/service name. This allows modules to inject their own parameters into services defined by other modules:
// Module A defines:
->addService(RepositoryContainer::class, singleton(object(RepositoryContainer::class)))
// Module A's arguments:
RepositoryContainer::class => [
'repositories' => [
AclRoleDto::entityType() => $service(AclRoleRepositoryImpl::class),
]
]
// Module B adds to the same composition:
RepositoryContainer::class => [
'repositories' => [
UserDto::entityType() => $service(UserRepositoryImpl::class),
]
]
Composition Pattern (Ordered Collections)¶
Used for extensible collections where modules contribute items with ordering:
// 1. Define the composition container
->addDefinition('cli:command:loader', object(
CommandLoader::class,
arguments(names()
->with('commands', compositionFactory(CompositionOrdered::selfFactory()))
)
))
// 2. Modules add items via arguments merging
'arguments' => [
'cli:command:loader' => [
'commands' => [
'ping' => compositionItem(object(PingCommand::class)),
'http:start' => compositionItem(object(HttpStartCommand::class), after: ['ping']),
]
]
]
Flyokai-Specific Gotchas¶
- Init phase has no container: DI config files run during init — the container doesn't exist yet. Use
$rootBootstrapmethods only, not$container->get(). - Arguments merging for compositions: Array keys in arguments are merged across modules — use unique keys to avoid overwriting another module's items.
- mustStart singletons: Used for HTTP server runner —
singleton(object(ServerRunnerImpl::class), true). Callingget()beforeapplication->start()throwsLifecycleException.