Service Container
Introduction
Dreamfork utilizes a straightforward service container that implements dependency injection. This approach ensures that the application injects various helper classes or facades by creating their declarations, but initializes them only when they are actually used. This mechanism contributes to a more efficient and optimized utilization of resources within the framework.
In many cases, you will interact with the service container indirectly, using convenient helper classes or facades designed for this purpose.
Binding
Static binding
Service container is accessible from any part of your application, by utilizing the app() helper function. This allows you to register your own classes with the dependency injection system, making them available for use throughout your application.
Upon registering a class with the app() injector, it checks whether an instance of that class already exists. If an instance does not exist, the injector creates one. This ensures that the class will have only one shared instance throughout the application, providing you with consistent access to that instance:
use App\Services\Notification;
app(Notification::class)->notify();
By utilizing app(), you can conveniently access the service container and resolve instances without explicitly calling make(). This enhances the simplicity and readability of your code when working with the dependency injection system. This means that the following code would achieve exactly the same result:
use App\Services\Notification;
app()->make(Notification::class)->notify();
Aliases
In addition to registering classes in the service container, you can create aliases for instances within the dependency injector. This allows you to avoid repetitive class imports in places where you want to utilize the created instance. Instead, you can use the alias directly:
use App\Services\Notification;
app()->alias('notification', Notification::class);
// Another file:
app('notification')->notify();
Singleton
The approaches mentioned earlier inherently act as Singletons, meaning they create only one instance for a given class by default. However, the service container provides a dedicated function for creating singletons, although it achieves the same end result as using make() or app() with a parameter. This dedicated function is named singleton():
use App\Services\Notification;
app()->singleton('notification', Notification::class);
app('notification')->notify();
One notable difference is that, in the case of such an instance definition, immediate use with method chaining is not possible. Initially, you need to create the singleton, and only then can you utilize it. Additionally, the singleton() method allows for the immediate definition of an alias.
Dynamic Binding
Dynamic Binding allows you to define classes using the bind() function, where the default setting for the third parameter, the flag, is false. This configuration specifies that, for the given class, a new instance will be created each time it is called. The previously mentioned singleton() function utilizes the bind() method but with the third parameter set to true, ensuring a single shared instance of the specified class.
use App\Services\Notification;
app()->bind('notification', Notification::class);
// Upon calling notify(), an instance of the Notification class is created.
app('notification')->notify();
// As the bound class is not shared, another instance is created.
app('notification')->notify();