Jump to content

Dependency Injection


Recommended Posts

Posted

Boas,

Alguém aqui tem aplicado / já aplicou o conceito de Dependency Injection em PHP? O conceito em teoria abre outras portas no desenvolvimento de código sustentável, e torna possível por exemplo desenhar um e-commerce com grandes melhorias em relação à adaptação da aplicação ao domínio / requisitos do cliente final. Seria um projecto interessante desenhar uma framework básica à volta do conceito.

Posted

Em termos de frameworks já existentes, a única com que já tive alguma e que tem DI foi a Laravel.

Pessoalmente, já implementei eu próprio uma variante de Dependency Injection cheio de customizações. Um sistema de módulos com estrutura hierárquica, onde qualquer módulo podia ter sub-módulos, cada módulo tinha um tipo (a classe), e podia pertencer a um grupo (Models, Views, Controllers, Resources, and so on). Em qualquer módulo podia aceder a uma instância de outro módulo utilizando o método load e passando um caminho do género Modulo1:Modulo2. A framework automaticamente, aplicava os alias (mais à frente), e com base nos módulos que já tinha carregados tentava resolver o pedido, e se não estivesse carregado, procurava no sistema de ficheiros pelo módulo (utilizando regras especificas mas bastante intuitivas: não era necessário registar os módulos, mas os seus nomes dos ficheiros determinavam os seus tipos e grupos, e as suas localizações determinavam os seus lugares hierárquicos). os alias permitiam coisas como substituir todos os módulos de um determinado grupo por outro grupo, ou todos pela mesma instância, e esse género de coisas, para além de poderem ter scopes diferentes, ou seja, o alias era aplicado a um módulo em especifico e aos seus sub-módulos. Ainda tinha mais umas funcionalidades, mas basicamente era isto.

Atualmente estou a usar essa framework minha no meu projecto de final de curso, e serve bem para as minhas necessidades especificas, mas precisava de algum trabalho extra para funcionar em projectos generalizados. Se tivesse mais algum tempo livre, gostava de reescrever a framework do zero com algum do conhecimento que ganhei entretanto, bem como da experiência de como as coisas deviam ser implementadas, de modo a torná-la mais flexível para outros projectos que tenham necessidades diferentes do meu, e mais extensível. Mas o tempo não dá para tudo. 🙂

PS: Não respondo a perguntas por mensagem que podem ser respondidas no fórum.

Posted

Acho que é importante especificar em que contexto se considera que "uma framework usa DI". Ao nível do core? Ao nível de extensões/plugins? Ao nível da utilização da API? É que a resposta não é lá muito linear...

Por exemplo, dizer que a Laravel usa DI... sim o seu Core usa DI e IoC, mas se olhar-mos para a API, http://laravel.com/docs, maior parte das páginas não obriga a que o utilizador use DI (isto com o intuito de simplificar a utilização), alias, a API são umas classes estáticas... (nem ainda vi como é que eles testam isto...) E deixo uma citação...

The main issue with static methods is that they introduce coupling, usually by hardcoding the dependency into your consuming code, making it difficult to replace them with stubs or mocks in your Unit-Tests. This violates the Open/Closed Principle and the Dependency Inversion Principle, two of theSOLID principles.

You are absolutely right that statics are considered harmful. Avoid them.

Posted (edited)

Tenho ideia de que as duas maiores frameworks Zend e Synfony são baseadas em DI. Para testes unitários, DI é o melhor.

O que elas praticam tem outro termo, Service Locator ... é semelhante mas tem diferenças fulcrais, principalmente tendo em conta o Tell, Don't Ask

Edited by yoda
Posted (edited)

@scorch,

essa framework que falaste não parece ter muito a ver com o caso, penso eu ..

@taviroquai,

Sim, há frameworks com DI de base e outras que o suportam, como CodeIgniter ou Kohana. Laravel tem DI de base mas como qualquer outra framework tentam vender ideias de como as coisas devem ser, e perdem-se aí.

Quando falei em framework básica era mesmo básica. Por exemplo um dos problemas que o DI resolve quando devidamente aplicado é que um pedido ajax num site vai obter uma resposta rápida, pois esse mesmo pedido tem poucas dependências, ao contrário do que acontece com a maior parte das frameworks em que o mesmo pedido ia passar pela verificação rotineira estabelecida como defeito para qualquer pedido.

DI é bastante simples entender, por em prática requer mais trabalho e atenção, mas a ideia é atingir algo deste género :

(exemplo simples, na verdade torna-se mais complexo)

$di = new DependencyInjector;

$di->register('config', $di->bind(function($c) { return new Config(); }));
$di->register('storage.driver', function($c) { return new Storage_Driver($c->resolve('config')); });
$di->register('storage', function($c) { return new Storage($c->resolve('storage.driver')); });
$di->register('user', function($c) { return new User($c->resolve('storage')); });

$user = $app->resolve('user'); // vai chamar todos os outros objectos consecutivamente dos quais depende

$user->getAll();

A ideia é um pouco registar todos as instâncias e propriedades "públicas" de forma a ter acesso a elas em qualquer lado sem ter de procurar pelo que se procura explicitamente. No exemplo abaixo a função pede explicitamente o que precisa para fazer o seu trabalho, e o DIC (Dependency Injection Container) injecta, como o nome diz, essas dependências quando a classe / função é chamada.

class Controller
{
       private $request;

       private $response;

public function __construct(Request $request, Response $response)
{
	$this->request = $request;
	$this->response = $response;
}

}
Edited by yoda
Posted (edited)

Quando falei em framework básica era mesmo básica.

Simples, existe o Pimple, da empresa por detrás da Symfony.

Acho que é importante especificar em que contexto se considera que "uma framework usa DI". Ao nível do core? Ao nível de extensões/plugins? Ao nível da utilização da API? É que a resposta não é lá muito linear...

Por exemplo, dizer que a Laravel usa DI... sim o seu Core usa DI e IoC, mas se olhar-mos para a API, http://laravel.com/docs, maior parte das páginas não obriga a que o utilizador use DI (isto com o intuito de simplificar a utilização), alias, a API são umas classes estáticas... (nem ainda vi como é que eles testam isto...) E deixo uma citação...

Laravel usa Facades, ou seja, apesar de ao utilizador final, parecerem classes estáticas, elas usam o IoC da framework. Ou seja, usando os magic methods do PHP, quando chamas um método de uma classe facade (uma classe estática que extende a classe Facade do Laravel), essa classe apenas serve de mirror para uma instância normalíssima da classe. E como as Facades usam o IoC, não é necessário modificar o código, basta mudar a classe que o IoC resolve. 🙂

More on this: http://stackoverflow.com/questions/19193532/laravel-4-facade-vs-di-when-to-use

Edited by scorch
  • Vote 1

PS: Não respondo a perguntas por mensagem que podem ser respondidas no fórum.

Posted (edited)

Boas,

Alguém aqui tem aplicado / já aplicou o conceito de Dependency Injection em PHP? O conceito em teoria abre outras portas no desenvolvimento de código sustentável, e torna possível por exemplo desenhar um e-commerce com grandes melhorias em relação à adaptação da aplicação ao domínio / requisitos do cliente final. Seria um projecto interessante desenhar uma framework básica à volta do conceito.

yoda para alguem que ja programa php há anos, não estou a ver que tenhas grande conhecimento de php, principalmente no OOP

podes ser expert em remendos ou a inverntar metodologias de programação, que é nisso que o php é conhecido...

tu VS um gaijo de faculdade um ano de experiencia que programe software em php asserio vai valer mais que tu no mercado...

devias aprender ruby on rails ou django ao menos nessas frameworks não se faz a cagada que fazem nessas empresas de esterco de media e design...

quando trabalhas em equipas de 10 ou mais pessoas ja tinhas aprendido e muito, agora a fazer projetos da caca nunca vais aprender muito...

se não reparaste o php é um monte de esterco só nos ultimos anos é que comecou a melhorar, dai a denominação "programação dos pobres"

já agora programas javascript orientado a objectos, ou fazes formularios da treta com um request ajax todo pipi ?

Edited by fdgdfgdfgd
Posted

@fdgdfgdfgd No fórum encorajamos um ambiente amigável, de respeito onde todos tenhamos algo a ganhar por aqui participar. Como este é o teu primeiro post, fica apenas aqui o aviso para que tenhas mais cuidado nos teus posts. Todos temos o direito à nossa opinião, mas ninguém tem o direito de tentar rebaixar os outros só para parecer grande.

PS: Não respondo a perguntas por mensagem que podem ser respondidas no fórum.

Posted (edited)

Bem me parecia que não estamos a falar da mesma coisa...

Para mim, uma coisa é DI, isto é, basicamente entre duas classes A e B, A não pode ser instanciada sem B, ou melhor, não faz sentido instanciar A sem B. Sim, já falamos que existem várias formas de "injectar" a dependência, seja no construtor ou num método... Mas isto não implica (ainda) um "contentor". Um contentor é mais à frente...

Por exemplo, em MapScript:

$map = new ms_Map();
$layer = new ms_Layer($map); // Não faz sentindo instanciar uma layer (camada) sem haver um mapa...

Um DI Container, para além de existir esta dependência, pelos exemplos que tenho visto (também do Pimple), aproxima-se mais a uma Registry (design pattern), ou seja, um contentor onde todos os serviços são "públicos" e podem comunicar entre si. É claro que vejo vantagens nisto, especialmente para o programador poder ter vários serviços num único local... no entanto, também vejo uma desvantagem: nem todos os serviços precisam comunicar entre si e conhecerem-se todos uns aos outros e isto pode-se traduzir em consumo de memória desnecessário se a complexidade da aplicação for considerável (nem sei lançar um número... digamos 100 classes).

My 50 cents...

PS. yoda já tinhas levantado esta questão anteriormente... se calhar não obtiveste aqui uma melhor resposta... 😕

EDIT:

Outra coisa que não gosto muito:

$foo = $di->resolve('bar'); // como é que eu sei que tipo de dados é $foo??? Nem a IDE vai conseguir resolver por type hint... 

// old school
$foo = Service::BarService(); // ah! $foo é do tipo Bar! Bem melhor...

Sim, resolver classes a partir de strings... permite coisas mais dinâmicas, mas será que ajuda o programador que se depara pela primeira vez com este tipo de programação? Acho que não...

Edited by taviroquai
Posted

Não implica um contentor, mas implica pelo menos uma classe na qual possamos definir as regras (a quais interfaces correspondes quais classes, etc...) e a quem depois possamos pedir os recursos, para que estas tratem de os inicializar, e se estes as tiverem, inicializar as suas dependências, e assim recursivamente. 🙂

PS: Não respondo a perguntas por mensagem que podem ser respondidas no fórum.

Posted

no entanto, também vejo uma desvantagem: nem todos os serviços precisam comunicar entre si e conhecerem-se todos uns aos outros e isto pode-se traduzir em consumo de memória desnecessário se a complexidade da aplicação for considerável (nem sei lançar um número... digamos 100 classes).

eu não vejo as frameworks a funcionar dessa maneira.

é de supor que os serviços só são instanciados on demand. isto quer dizer que apesar de estar tudo acessível, a instanciação só é feita quando for necessária a sua utilização e ainda não tiver sido feita anteriormente.

IRC : sim, é algo que ainda existe >> #p@p
Posted

eu não vejo as frameworks a funcionar dessa maneira.

é de supor que os serviços só são instanciados on demand. isto quer dizer que apesar de estar tudo acessível, a instanciação só é feita quando for necessária a sua utilização e ainda não tiver sido feita anteriormente.

Exato, é como o HappyHippyHippo diz. Aliás, para além do desacoplamento entre os módulos (e uma consequência disto) é o facto de apenas os módulos necessários serem carregados, pois os outros não estão associados/ligados/conectados. Ou seja, a cada request apenas é executado uma sub-aplicação da aplicação total, ou seja, o benefício é, de facto, proporcional quanto maior for a dimensão da aplicação. 🙂

PS: Não respondo a perguntas por mensagem que podem ser respondidas no fórum.

Posted

Outra coisa que não gosto muito:

$foo = $di->resolve('bar'); // como é que eu sei que tipo de dados é $foo??? Nem a IDE vai conseguir resolver por type hint...

// old school
$foo = Service::BarService(); // ah! $foo é do tipo Bar! Bem melhor...

Sim, resolver classes a partir de strings... permite coisas mais dinâmicas, mas será que ajuda o programador que se depara pela primeira vez com este tipo de programação? Acho que não...

Não é bem essa a ideia, a ideia é ter um $di->user (user autênticado) que é a mesma instância em qualquer parte do script, não ter que adivinhar o que a nossa nova função para um sistema já existente requira (por estar explícito na construção de objectos), poder fazer alterações mínimas no código para testar sem ter de editar 40 linhas para se testar uma delas, ...

Posted

é assim, eu tenho tando a seguir o topico, mas a verdade é que ainda nao apanhei XD as vezes sou um pouco lerdo.

Alguem pode dar ai uma definição assim por base, para leigos, do que realmente se trata isto, e para que realmente serve, cenarios em que faça logica usar isto...

isto quando se é autodidacta há certas coisas que so passados uns anos é que nos deparamos... mas tenho gosto em evoluir, por isso se alguem se quizer chegar a frente e explicar-me, ficaria muito grato 🙂

B2R » Beat2Revolution v3.0b | Regista e divulga-nos

beat2revolution.net
Posted

Numa palavra: Decoupling

  • Vote 1

“There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult.”

-- Tony Hoare

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.