Neste artigo, veremos alguns exemplos de uso do componente Symfony DependencyInjection. Você aprenderá o básico da injeção de dependência, que permite um código mais limpo e modular, e verá como usá-lo em suas aplicações PHP com o componente Symfony.
O que é o componente DependencyInjection do Symfony?
O componente DependencyInjection do Symfony fornece uma maneira padrão de instanciar objetos e lidar com o gerenciamento de dependências em seus aplicativos PHP. O coração do componente DependencyInjection é um contêiner, que contém todos os serviços disponíveis no aplicativo.
Durante a fase de bootstrap do seu aplicativo, você deve registrar todos os serviços do seu aplicativo no contêiner. Em um estágio posterior, um contêiner é responsável por criar serviços conforme necessário. Mais importante, um container também é responsável por criar e injetar dependências dos serviços.
O benefício dessa abordagem é que você não precisa codificar o processo de instanciar objetos, pois as dependências serão detectadas e injetadas automaticamente. Isso cria um acoplamento fraco entre as partes do seu aplicativo.
Neste artigo, exploraremos como você pode liberar o poder do componente DependencyInjection. Como de costume, começaremos com as instruções de instalação e configuração e implementaremos alguns exemplos do mundo real para demonstrar os principais conceitos.
Instalação e configuração
Nesta seção, iremos em frente e instalaremos o componente DependencyInjection. Suponho que você já tenha instalado o Composer em seu sistema, pois precisaremos dele para instalar o componente DependencyInjection disponível no Packagist.
Então vá em frente e instale o componente DependencyInjection usando o seguinte comando.
$composer require symfony/dependency-injection
Isso deveria ter criado o compositor.json arquivo, que deve ficar assim:
{
"require": {
"symfony/dependency-injection": "^5.4"
}
}
Também instalaremos alguns outros componentes que serão úteis em nossos exemplos.
Se você deseja carregar serviços de um arquivo YAML em vez de defini-lo no código PHP, é o componente Yaml que vem em socorro, pois ajuda a converter strings YAML em tipos de dados compatíveis com PHP e vice-versa.
$composer require symfony/yaml
Finalmente, instalaremos o componente Config, que fornece várias classes de utilitários para inicializar e lidar com valores de configuração definidos em diferentes tipos de arquivos, como YAML, INI e XML. No nosso caso, vamos usá-lo para carregar serviços do arquivo YAML.
$composer require symfony/config
Vamos modificar o compositor.json arquivo para se parecer com o seguinte.
{
"require": {
"symfony/dependency-injection": "^5.4",
"symfony/yaml": "^5.4",
"symfony/config": "^5.4"
},
"autoload": {
"psr-4": {
"Services\": "src"
},
"classmap": ["src"]
}
}
Como adicionamos um novo classmap entrada, vamos em frente e atualizar o autoloader do compositor executando o seguinte comando.
$composer dump -o
Agora, você pode usar o Services namespace para carregar automaticamente as classes sob o src diretório.
Então essa é a parte da instalação, mas como você deve usá-la? Na verdade, é apenas uma questão de incluir o autoload.php arquivo criado pelo Composer em seu aplicativo, conforme mostrado no trecho a seguir.
Como trabalhar com um contêiner
Nesta seção, veremos um exemplo para demonstrar como você pode injetar serviços em um contêiner. Um contêiner deve atuar como um repositório central que contém todos os serviços em seu aplicativo. Mais tarde, poderíamos usar um contêiner para buscar serviços conforme necessário.
Para começar, vamos definir um serviço bem básico em src/DemoService.php com o seguinte conteúdo.
Este é um serviço muito simples, que apenas implementa o
helloWorldmétodo para o momento.Em seguida, vá em frente e crie o basic_container.php arquivo com o seguinte conteúdo na raiz do seu aplicativo.
register('demo.service', 'ServicesDemoService'); // fetch service from the service container $demoService = $containerBuilder->get('demo.service'); echo $demoService->helloWorld();Para começar, instanciamos o
ContainerBuilderobjeto com onew ContainerBuilder()construtor. A seguir, utilizamos oregistermétodo doContainerBuilderobjeto para injetar nosso serviço personalizadoServicesDemoServiceno recipiente. odemo.serviceatua como um alias para o nosso serviço.Por fim, usamos o
getmétodo doContainerBuilderobjeto para buscar nosso serviço do contêiner e usá-lo para chamar ohelloWorldmétodo.Então essa foi uma demonstração básica de como trabalhar com um container. Na próxima seção, estenderemos este exemplo para explorar como as dependências de classe são resolvidas usando um contêiner.
Um exemplo do mundo real
Nesta seção, criaremos um exemplo que demonstra como as dependências de classe são resolvidas usando o componente DependencyInjection.
Para demonstrá-lo, criaremos um novo serviço
DependentServiceque exige oDemoServiceservice, criado na seção anterior, como uma dependência. Assim, veremos como oDemoServiceservice é injetado automaticamente como uma dependência quando oDependentServiceserviço é instanciado.Vá em frente e crie o src/DependentService.php arquivo com o seguinte conteúdo para definir o
DependentServiceserviço.demo_service = $demoService; } public function helloWorld() { return $this->demo_service->helloWorld(); } }Como você pode ver, o
ServicesDemoServiceserviço é necessário para instanciar oDependentServiceserviço.Em seguida, vá em frente e crie o di_container.php arquivo com o seguinte conteúdo.
register('demo.service', 'ServicesDemoService'); // add dependent service into the service container $containerBuilder->register('dependent.service', 'ServicesDependentService') ->addArgument(new Reference('demo.service')); // fetch service from the service container $dependentService = $containerBuilder->get('dependent.service'); echo $dependentService->helloWorld();Estamos usando o mesmo
registermétodo para injetar nosso serviço personalizadoServicesDependentServiceno recipiente.Além disso, também usamos o
addArgumentmétodo para informar o container sobre a dependência doDependentServiceserviço. Nós usamos oReferenceclasse para informar ao container que ele precisa injetar odemo.serviceserviço quando odependent.serviceserviço é instanciado. Dessa forma, uma dependência é injetada automaticamente conforme necessário!Por fim, usamos o
getmétodo doContainerBuilderobjeto para buscar odependent.serviceserviço doContainerBuilderobjeto e usei-o para chamar ohelloWorldmétodo.Dessa forma, o componente DependencyInjection fornece uma maneira padrão de instanciar objetos e injetar dependências em seu aplicativo.
Como carregar serviços dinamicamente usando o arquivo YAML
Nesta seção, exploraremos como você pode carregar serviços dinamicamente do arquivo YAML. Basicamente, atualizaremos o exemplo discutido na seção anterior.
Além do componente DependencyInjection, também precisaremos de mais dois componentes Symfony para implementar o exemplo YAML—Config e Yaml. Lembre-se de que já instalamos esses dois componentes no Instalação e configuração seção junto com o próprio componente DependencyInjection. Então estamos prontos!
Vá em frente e crie o services.yaml arquivo com o seguinte conteúdo na raiz do seu aplicativo.
services: demo.service: class: ServicesDemoService dependent.service: class: ServicesDependentService arguments: ["@demo.service"]Como você pode ver, é bastante simples definir serviços usando a sintaxe YAML. Para definir as dependências do seu serviço, você precisará usar o
argumentschave.Em seguida, vá em frente e crie o di_yaml_container.php arquivo com o seguinte conteúdo.
load('services.yaml'); // fetch service from the service container $serviceOne = $containerBuilder->get('dependent.service'); echo $serviceOne->helloWorld();Tudo é praticamente o mesmo, exceto que estamos carregando serviços do services.yaml arquivo em vez de defini-lo no próprio código PHP. Isso permite que as dependências do aplicativo sejam definidas dinamicamente.
Como injetar um serviço preguiçoso
Em alguns casos, você deseja injetar um serviço lento. Às vezes, você tem um serviço que é muito pesado para instanciar. Portanto, se você deseja injetar esse serviço, deseja que ele seja injetado apenas quando for verdade necessário, e não antes disso. A resposta a esta pergunta é um serviço preguiçoso.
Mas, como isso funciona exatamente? Na verdade, quando você configura um serviço lento, em vez de injetar o serviço real, um proxy do serviço é injetado. Na superfície, um serviço de proxy funciona como o serviço real, mas assim que você começa a interagir com o serviço de proxy, o serviço real é instanciado.
Para usar serviços preguiçosos, precisamos instalar o
symfony/proxy-manager-bridgepacote. Vamos fazer isso em primeiro lugar.$composer require symfony/proxy-manager-bridgeA seguir, revisaremos o di_container.php exemplo para entender como usar o gerenciador de proxy para criar e injetar um serviço de proxy.
Vá em frente e substitua o código do di_container.php arquivo com o seguinte conteúdo.
get('demo.service'); // fill your object with values here return true; // confirm that initialization occurred correctly }; $proxy = $factory->createProxy('ServicesDemoService', $initializer); // code for creating proxy ends global $containerBuilder; $containerBuilder = new ContainerBuilder(); $containerBuilder->register('demo.service', 'ServicesDemoService'); $containerBuilder->register('dependent.service', 'ServicesDependentService')->addArgument($proxy); $dependentService = $containerBuilder->get('dependent.service'); echo $dependentService->helloWorld();Em primeiro lugar, criamos uma instância do
LazyLoadingValueHolderFactoryclasse. A seguir, usamos ocreateProxymétodo desta classe para definir como a instância doServicesDemoServiceclasse será criada. O segundo argumento docreateProxyé uma função anônima, que será chamada quando a instância real da classe precisar ser instanciada em vez de um objeto proxy. E assim, a função anônima lida com a lógica de criar uma instância real.Tirando isso, é praticamente a mesma coisa. Depois que a instância de proxy for criada, vamos passá-la no
addArgumentmétodo, em vez de criar uma instância com oReferenceclasse.O benefício dessa abordagem é que sempre que criamos uma instância do
ServicesDependentServiceclasse, ele não criará o objeto real daServicesDemoServiceclass, em vez disso, ele criará um objeto proxy. O objeto real daServicesDemoServiceclasse será criada somente quando você chamar qualquer método dela.Para confirmar, você pode simplesmente despejar o
$dependentServiceobjeto, e você deve ver algo assim.ServicesDependentService Object ( [demo_service:ServicesDependentService:private] => ProxyManagerGeneratedProxy__PM__ServicesDemoServiceGeneratedccdf8241e892da36c12500ed72d82829 Object ( [valueHoldera1fd8:ProxyManagerGeneratedProxy__PM__ServicesDemoServiceGeneratedccdf8241e892da36c12500ed72d82829:private] => [initializere3996:ProxyManagerGeneratedProxy__PM__ServicesDemoServiceGeneratedccdf8241e892da36c12500ed72d82829:private] => Closure Object ( [parameter] => Array ( [&$wrappedObject] =>[$proxy] => [$method] => [$parameters] => [&$initializer] => ) ) ) ) Como você pode ver, ele criou o objeto proxy em vez do real
ServicesDemoServiceobjeto.Se você não tivesse usado o método proxy, a saída teria sido assim.
ServicesDependentService Object ( [demo_service:ServicesDependentService:private] => ServicesDemoService Object ( ) )Como você pode ver, ele criou uma instância do
ServicesDemoServiceclasse!Então é assim que funciona o carregamento preguiçoso de serviços!
Conclusão
O componente Symfony DependencyInjection foi o centro das atenções neste tutorial. Vimos como instalar e configurar o DependencyInjection, bem como alguns exemplos do mundo real de como ele pode ser usado.
Estou realmente fascinado e animado com os componentes desacoplados do framework Symfony que você pode simplesmente escolher para sua aplicação. Conecte-os ao seu código e eles simplesmente funcionam! Em suma, só posso ver os benefícios dessa abordagem de estrutura para nossa comunidade PHP!
[ad_2]