composer require weew/kernel
Kernel is responsible for the bootstrap process of service providers. It offers you a easy and intuitive way to register your own providers. The boot process consists of three steps - instantiation
, initialization
and booting
. There is also an additional step - shutdown
. This gives your providers a lot of flexibility on when to do what.
Any class can be used as a provider. If the provider has any of these methods configure
, initialize
, boot
, shutdown
, the container will invoke them accordingly. It does not require a specific interface. This is by choice, I'll explain why I chose this solution in one of the future readme updates.
class MyServiceProvider {}
// or
class MyServiceProvider {
public function configure() {}
public function initialize() {}
public function boot() {}
public function shutdown() {}
}
It is fairly easy to create a kernel and register your own providers.
$kernel = new Kernel();
$kernel->addProviders([
MyServiceProvider::class,
AnotherServiceProvider::class,
]);
When you configure the kernel, all of its service providers get instantiated and configured.
$kernel->configure();
When you initialize the kernel, all of its service providers get initialized.
$kernel->initialize();
On boot, all service providers will be booted. This is a good place to setup your provider and do some work.
$kernel->boot();
This will shutdown the kernel and all of its providers.
$kernel->shutdown();
The kernel comes without a container. Out of the box the service providers will be very limited since they have no way to share anything. There are several workarounds for this.
The easiest way to share data between providers is to use kernel's shared arguments.
class MyProvider {
public function boot(IDictionary $shared) {
$shared->get('container')['foo'] = 'bar';
}
}
$kernel = new Kernel();
$container = [];
$kernel->getSharedArguments()->set('container', $container);
$kernel->addProvider(MyProvider::class);
A better way to enable container access for your providers is to replace the default implementation of the IProviderInvoker
with your own. In this example I'll be using this powerful container.
class ContainerProviderInvoker implements IProviderInvoker {
private $container;
public function __construct(IContainer $container) {
$this->container = $container;
}
public function create($providerClass, IDictionary $shared) {
$this->container->get($providerClass, ['shared' => $shared]);
}
public function configure($provider, IDictionary $shared) {
$this->container->callMethod($provider, 'configure', ['shared' => $shared]);
}
public function initialize($provider, IDictionary $shared) {
$this->container->callMethod($provider, 'initialize', ['shared' => $shared]);
}
public function boot($provider, IDictionary $shared) {
$this->container->callMethod($provider, 'boot', ['shared' => $shared]);
}
public function shutdown($provider, IDictionary $shared) {
$this->container->callMethod($provider, 'shutdown', ['shared' => $shared]);
}
}
$container = new Container();
$invoker = new ContainerProviderInvoker($container);
$kernel = new Kernel($invoker);
// or
$kernel->setProviderInvoker($invoker);
From now on all providers will benefit from constructor and method injection and will be able to share anything in the container. Depending on which container package you use the IProviderInvoker
implementation may vary, but the idea stays the same.
There is an integration available for the weew/container container. See weew/kernel-container-aware.
- PHP Container works very well together with this package.