Application Container & Inversion of Control

Inversion of control (IoC) is a software design principle in which class (service) construction is removed from the flow of control of the application and is handled internally by what is know as a "container" or the "application container". Disco extends and provides a wrapper around the Pimple Container via the `Disco\classes\App` class.

Services registered in the container are identified by a key and a value, with the key being how the service is accessed in the container and the value being what is to be constructed (a class) or called ( a function).

Standard services in the container will only be constructed once and that construction is deferred until the service is first called. This means that if in the flow of control of the application we did not end up using a service, then it will never have been constructed.

Factory services return a new instance of the service on every call.

Protected services are treated as functions and will either always return a call to the Closure function specified in make, or a call to the magic method __call on your class.

You can at any point in the application life cycle re-register or swap any the services in the container.

Registering Services in the Container #

// Register a standard service
App::make('YourService', 'App\service\TheService');

// Register a standard service via a Closure function
App::make('YourService', function(){
    $service = new App\service\TheService;
    $service->warmUp();
    return $service;
});

// Register multiple services at once
App::registerServices([
    'User' => 'App\service\User',
    'Product' => 'App\service\Product'
]);


// Register a factory service (You can pass a Closure function as well)
App::makeFactory('MovieTicket', 'App\helper\MovieTicket');


// Register a protected service
App::makeProtected('Extension', function($path){
    return pathinfo($path, PATHINFO_EXTENSION);
});


// Extend or swap an already instantiated service
App::extend('YourService', 'App\service\DifferentService');

Accessing the Container #

// Use the with method to get a service from the container
$service = App::with('View');

// If you call a service that hasn't been registered in the container, the 
// container will try to construct a class defined by the key you accessed,
// if it was successful the service will be registered in the container for future use.
$users = App::with('App\model\User')->select('name')-data();


// If it was protected and acts as a function
$ext = App::with('Extension')('some/file.mp3');



// If you want to get the actual container class ie the `Disco\classes\App` instance
$app = App::instance();
// Or
$app = app();

// You can interact with $app now the same as you would with the Facade
// Plus you can interact with it as an array since the container implements array access
// Hence powering the container.
$app['SomeService']->callAMethod();

$app->with('Service')->nice();

// Or you can get a service by passing a string to the app method
app('SomeService')->method();