Skip to main content

Service Providers

Overview

Service Providers are a convenient way to organize and register services within DomainFlow Core. They let you encapsulate logic for binding services, bootstrapping functionality, and optionally deferring expensive or optional features until needed. By grouping related services in a single provider, you keep your application tidy and make it simpler to manage multiple services at once.


Key Concepts

  • Registration: A provider’s main job is to bind services into the application so they can be resolved when needed.
  • Boot: Once registered, a provider can perform additional setup in its boot() method—especially useful if the provider needs to react to other services now being available.
  • Deferred Loading: If you mark a provider as deferred, it only registers its services on demand, improving startup performance for applications with many optional services.

Method Descriptions (Application-Level)

Below are the main methods on your Application instance to register, manage, and load service providers.

registerProvider($provider)

Signature

public function registerProvider(ServiceProviderInterface $provider): void

Purpose Registers a service provider with the application. If the provider is not deferred, it immediately calls the provider’s register() method. If the application has already booted, it then calls boot() on the provider.

ParameterTypeRequired?Description
$providerServiceProviderInterfaceYesAn object that implements the methods needed to register and optionally boot services.

Usage Example

$app->registerProvider(new MyCustomServiceProvider());

unregisterProvider($providerClass)

Signature

public function unregisterProvider(string $providerClass): void

Purpose Removes a provider from the application, along with any deferred services it might have registered. This is helpful if you need to dynamically disable certain functionality.

ParameterTypeRequired?Description
$providerClassstringYesThe fully qualified class name of the provider to remove.

Usage Example

$app->unregisterProvider(\Acme\Example\ExampleServiceProvider::class);

getProviders()

Signature

public function getProviders(): array

Purpose Returns an array of all currently registered providers. You might use this for debugging or when you need to iterate over each provider for specialized logic.

ParameterTypeRequired?Description
NoneN/AN/AN/A

Usage Example

foreach ($app->getProviders() as $provider) {
// Inspect or interact with the provider
}

loadDeferredProviders()

Signature

public function loadDeferredProviders(): void

Purpose Forces the application to register any providers marked as deferred—useful if you want everything loaded up front rather than waiting for on-demand resolution.

ParameterTypeRequired?Description
NoneN/AN/AN/A

Usage Example

// If you want no lazy loading:
$app->loadDeferredProviders();

hasProvider($providerClass)

Signature

public function hasProvider(string $providerClass): bool

Purpose Checks if a particular provider is already registered. Useful to prevent multiple registrations or to confirm that a provider is active.

ParameterTypeRequired?Description
$providerClassstringYesThe fully qualified class name of the provider to check for.

Usage Example

if (!$app->hasProvider(\Vendor\Logging\LoggingProvider::class)) {
$app->registerProvider(new LoggingProvider());
}

Method Descriptions (Inside a Service Provider)

To create your own provider, you can implement the ServiceProviderInterface or extend a base provider class. The interface typically expects you to define:

register($app)

Signature

public function register(Application $app): void

Purpose Where you bind services into the application, e.g., $app->bind('SomeKey', ...). This method is called when the provider is first registered—either immediately or on-demand if deferred.

ParameterTypeRequired?Description
$appApplicationYesReference to the main application object

boot($app)

Signature

public function boot(Application $app): void

Purpose Runs after register()—useful for tasks that rely on services being bound already. If the application is already booted when you register a provider, boot() is called immediately after register() completes.

ParameterTypeRequired?Description
$appApplicationYesReference to the main application object

provides()

Signature

public function provides(): array

Purpose Returns an array of “service keys” that this provider is responsible for. When marked as deferred, the application uses this list to see if your provider should be loaded.

ParameterTypeRequired?Description
NoneN/AN/AMust return a list of string keys.

isDeferred()

Signature

public function isDeferred(): bool

Purpose Indicates whether your provider is eligible for lazy-loading (i.e., only loaded when one of its provides() services is requested).

ParameterTypeRequired?Description
NoneN/AN/AReturn true for lazy-loading.

Comparative Descriptions

  • Immediate vs. Deferred Registration
  • If isDeferred() returns false, register() happens right away.
  • If true, the provider’s services get bound only when their keys are first requested or if you explicitly call loadDeferredProviders().
  • register() vs. boot()
  • register() is for binding or configuring services.
  • boot() is for tasks that rely on the services being fully registered, or for hooking into the application after it’s been initialized.

Practical Examples

class LoggingServiceProvider extends AbstractServiceProvider
{
public bool $defer = true; // This can be set to false for immediate loading

protected array $providedServices = [
'Logger'
];

public function register(Application $app): void
{
// Bind the service
$app->bind('Logger', function ($app) {
return new Logger(/* ... */);
});
}

public function boot(Application $app): void
{
// Possibly attach the logger to events or load additional config
}
}

// Usage in your app:
$app->registerProvider(new LoggingServiceProvider());

// If you want to load it immediately:
$app->loadDeferredProviders();

// Retrieve the logger:
$logger = $app->get('Logger'); // triggers deferred registration if not yet loaded

Extensibility

  • Multiple Services per Provider: You can return many service keys in provides(). This makes it simple to group related services (e.g., “Mailer” and “MailQueue”).
  • Conditional Providers: Some teams use environment checks to decide whether to register certain providers. For instance, only register a debug provider if you’re in development mode.
  • Plugin Systems: If your application supports add-ons, you can treat each add-on as a “service provider” that integrates new functionality without cluttering your core code.

Service providers keep your code organized and encourage modularity, making it easier to share or reuse common functionality across projects.