Provedores de Serviços
Provedores de serviços (service providers) são classes que agrupam o registro de serviços no contêiner da aplicação. O próprio PivotPHP usa provedores para inicializar seus serviços internos (contêiner, eventos, logging, hooks, extensões e roteamento).
Escrevendo um Provedor
Todo provedor estende a classe abstrata PivotPHP\Core\Providers\ServiceProvider. O construtor recebe a instância de Application, disponível em $this->app.
| Método | Obrigatório | Quando é chamado |
|---|---|---|
register(): void |
Sim | Imediatamente, quando o provedor é registrado |
boot(): void |
Não | Durante $app->boot(), depois que todos os provedores foram registrados |
<?php
namespace App\Providers;
use App\Services\Mailer;
use PivotPHP\Core\Providers\ServiceProvider;
class MailServiceProvider extends ServiceProvider
{
public function register(): void
{
// Apenas vincule serviços ao contêiner aqui
$this->app->singleton(Mailer::class, function () {
return new Mailer($_ENV['MAIL_FROM'] ?? 'noreply@exemplo.com');
});
}
public function boot(): void
{
// Aqui todos os provedores já foram registrados:
// é seguro resolver serviços, adicionar rotas ou middleware
$this->app->get('/mail/from', function ($req, $res) {
return $res->json(['from' => $this->app->make(Mailer::class)->from]);
});
}
}
O método register
Use register() somente para vincular serviços ao contêiner. Os métodos disponíveis em $this->app para isso são:
$this->app->bind('report', fn() => new Report()); // nova instância a cada resolução
$this->app->singleton(Cache::class, fn() => new FileCache()); // instância compartilhada
$this->app->instance('api.key', $_ENV['API_KEY'] ?? ''); // valor já construído
$this->app->alias('cache', Cache::class); // nome alternativo
O método boot
boot() é chamado uma única vez, dentro de $app->boot() (que run() e handle() executam automaticamente se ainda não tiver sido chamado). Nesse ponto, todos os provedores já executaram register(), então você pode resolver serviços com $this->app->make(), registrar rotas e middleware.
Registrando Provedores
Com $app->register()
register() aceita o nome da classe ou uma instância:
use PivotPHP\Core\Core\Application;
use App\Providers\MailServiceProvider;
$app = new Application();
$app->register(MailServiceProvider::class);
// ou
$app->register(new MailServiceProvider($app));
$app->run();
Registrar a mesma classe duas vezes não tem efeito: a segunda chamada é ignorada.
Pela configuração app.providers
Durante o boot, a aplicação também registra as classes listadas na chave de configuração app.providers:
$app->getConfig()->set('app.providers', [
App\Providers\MailServiceProvider::class,
]);
Registre antes do boot
O boot() de um provedor só é executado se ele for registrado antes de $app->boot(). Um provedor registrado depois disso tem seu register() executado normalmente, mas o seu boot() nunca é chamado. Registre todos os provedores antes de $app->run()/$app->handle().
provides() e isDeferred()
A classe base também declara provides(): array (retorna []) e isDeferred(): bool (retorna false). A Application não usa esses métodos: não existe carregamento adiado (deferred) de provedores — todo provedor registrado executa register() imediatamente.
Provedores Internos
A aplicação registra automaticamente, nesta ordem:
| Provedor | Responsabilidade |
|---|---|
ContainerServiceProvider |
Serviços básicos do contêiner |
EventServiceProvider |
Despachante de eventos (PSR-14) |
LoggingServiceProvider |
Logger (PSR-3) |
HookServiceProvider |
Sistema de hooks (actions/filters) |
ExtensionServiceProvider |
Gerenciador de extensões |
RoutingServiceProvider |
Roteador |
Todos ficam no namespace PivotPHP\Core\Providers.
Testando um Provedor
use App\Providers\MailServiceProvider;
use App\Services\Mailer;
use PivotPHP\Core\Core\Application;
use PHPUnit\Framework\TestCase;
class MailServiceProviderTest extends TestCase
{
public function testRegistraMailerComoSingleton(): void
{
$app = new Application();
$app->register(MailServiceProvider::class);
$this->assertTrue($app->has(Mailer::class));
$this->assertSame($app->make(Mailer::class), $app->make(Mailer::class));
}
}
Boas Práticas
- Um provedor por responsabilidade: agrupe apenas serviços relacionados.
register()só vincula: não resolva outros serviços dentro deregister(); faça isso emboot().- Registre antes do boot: provedores registrados depois de
$app->boot()não têmboot()executado. - Evite trabalho pesado: prefira closures em
bind/singletonpara que os serviços só sejam construídos quando resolvidos.