The backbone of Framework Factory is its versatile PSR-11 compliant IoC container. IoC containers typically allow services, or dependencies, to be loaded into them in many ways. Framework Factory, for instance, uses Service Providers to accomplish the installation, modification and customization of these services.
A service provider is a class or module that tells the container how to create, configure, and register services so they can be automatically resolved and injected into other parts of an application. Framework Factory uses a specific approach to creating service providers, using internal libraries to handle the heavy lifting of certain tasks such as the injection of the library, the implementation of the Context API and executing its lifecycle hooks.
For questions about creating and building services, please feel free to review the Services section of the docs before proceeding.
Each service provider must extend Framework Factory's base
ServiceProviderclass. Theregister()method of that class provides access to the containers binding methods.
<?php
namespace App\Providers;
use FrameworkFactory\Contracts\Providers\ServiceProvider;
class MessageProvider extends ServiceProvider
{
public function register(): void
{
// ...
}
}Below is an example of the code required for your typical service provider class. Each service that is bound to the container is mounted by calling the
bind()method.
<?php
namespace App\Providers;
use FrameworkFactory\Contracts\Providers\ServiceProvider;
use App\Services\Message as MessageService;
class MessageProvider extends ServiceProvider
{
public function register(): void
{
$this->bind(MessageService::class, fn () => new MessageService());
}
}There is an alternative approach to binding a service to the container from within a service provider. This method uses the
CreatesBindingattribute. This technique is useful when you want to register a non-deferred service and bind it to the container, or a service that has no arguments needing to be passed through its constructor.When implementing the
CreatesBindingattribute, the first parameter is the ID of the binding you're registering and the second parameter is the class you'd like to register.
<?php
namespace App\Providers;
use FrameworkFactory\Attributes\Providers\CreatesBinding;
use FrameworkFactory\Contracts\Providers\ServiceProvider;
use App\Services\Message as MessageService;
#[CreatesBinding('message', MessageService::class)]
class MessageProvider extends ServiceProvider {}When using this approach, the
register()method can be omitted since theCreatesBindingattribute foregoes this entirely, andbind()'s the new service to the container internally.
Lazy-loading is a programming technique where data, objects, modules, or resources are not loaded into memory until they are actually needed, rather than being loaded upfront. This can improve application startup time, reduce memory usage, lower network traffic, and make large applications feel more responsive because unnecessary work is deferred.
Common examples include loading database relationships only when accessed, importing JavaScript modules on demand, or loading images as a user scrolls through a page. However, lazy-loading also has disadvantages: it can introduce small delays when a resource is first requested, make application behavior less predictable, increase code complexity, and sometimes lead to issues such as excessive database queries (for example, the "N+1 query" problem in ORMs) if not implemented carefully. In general, lazy-loading trades immediate resource consumption for deferred execution, which can significantly improve efficiency when many resources may never actually be used.
Below is an example of the code required for lazy loading. This is done by calling the
singleton()method. Additionally, we will want to implement theprovides()method - which returns an array of ID's for singleton services that have been added to the container within that Service Provider class.
<?php
namespace App\Providers;
use FrameworkFactory\Contracts\Providers\ServiceProvider;
use App\Services\Message as MessageService;
class MessageProvider extends ServiceProvider
{
public function register(): void
{
$this->singleton(MessageService::class, fn () => new MessageService());
}
public function provides(): array
{
return [
MessageService::class
];
}
}Accessing services can be done by calling the
Application::get()method from anywhere within the application. This method returns the service that has been bound to the container, by using the assigned ID as an argument.
<?php
use App\Services\Message as MessageService;
use FrameworkFactory\Application;
$message = Application::get(MessageService::class);
echo $message->display('This is my message to the world!');Alternately, Accessors can be used to access services that have been bound to the container.
<?php
use App\Accessors\Message;
$message = Message::display('This is my message to the world!');
echo $message;Once a dependency has been loaded into the container using a service provider, and the container has been built, we may want to interact with it prior to calling it from within the application. The
boot()method of a service container is executed after the container has been built, and all dependencies have been loaded into it which allows them to be interacted with.
<?php
public function boot(): void
{
// do something ...
}- See Also: Service Classes
- See Also: Lifecycle Hooks
- See Also: Context API