Back-End

20 mai, 2014

Autoinjeção de dependências em objetos PHP

Publicidade

Eu tenho que admitir que realmente não sei qual o melhor título para este artigo. Mas coloquei, por fim, “autoinjeção de dependências em objetos PHP”. Eu sei que não é muito descritivo. Deixe-me explicar um pouco – eu queria automatizar o “Princípio de Hollywood” (“Não nos chame, nós chamamos você”), o lema da injeção de dependência. A Ideia é simples. Imagine um “controller”.

class Controller
{
    public function hi($name)
    {
        return "Hi $name";
    }
}

Podemos automatizar facilmente a ação “hi”.

$controller = new Controller();
echo $controller->hi("Gonzalo");

Ou talvez se estamos construindo um framework e o nosso class name e action name dependem do input do usuário.

$class = "Controller";
$action = "hi";
$arguments = ['name' => "Gonzalo"];

echo call_user_function_array([new $class, $action], arguments);

Mas imagine que você queira permitir algo assim:

class Controller
{
    public function hi($name, Request $request)
    {
        return "Hi $name " .$request->get('surname');
    }
}

Agora precisamos inventar o objeto Request com a nossa ação “hi”, mas não sempre. Apenas quando o usuário setar uma variável com o type “Request”. Imagine que você também quer permitir esse tipo de injeção no constructor. Pode ser que precise usar o Reflections para criar nossa instância e fazer o call to action. Algumas vezes, tenho que trabalhar com frameworks padrão e aplicações PHP legadas. Fiz isso em alguns projetos, mas agora eu quero criar uma biblioteca para automatizar essa operação.

A ideia é usar o Container de Injeção de Dependência (no meu caso, Pimple), e recuperar a dependência do container (se disponível). Eu não posso usar a keyword “new” para criar a instância e também não posso chamar a ação diretamente.

Um exemplo de uso é:

class Foo
{
    public function hi($name)
    {
        return "Hi $name";
    }
}

class Another
{
    public function bye($name)
    {
        return "Bye $name";
    }
}

class Bar
{
    private $foo;

    public function __construct(Foo $foo, $surname = null)
    {
        $this->foo     = $foo;
        $this->surname = $surname;
    }

    public function hi(Another $another, $name)
    {
        return $this->foo->hi($name . " " . $this->surname) . ' ' . $another->bye($name);
    }
}

$container = new Pimple();
$container['name'] = "Gonzalo2";

$builder = new G\Builder($container);

$bar = $builder->create('Bar', ['surname' => 'Ayuso']);
var_dump($builder->call([$bar, 'hi']));

var_dump($bar->hi(new Another(), 'xxxxx'));

Nossa biblioteca tenta recuperar a dependência do DIC. Se não consegue fazer isso, ela cria uma nova instância.

A “mágica” está toda na classe Builder. Você pode ver a biblioteca no meu GitHub.

***

Artigo traduzido pela Redação iMasters, com autorização do autor. Publicado originalmente em http://gonzalo123.com/2014/03/03/auto-injecting-dependencies-in-php-objects/