Dependency Injection no PHP 5.3
Guilherme Blanco – Yahoo!
2
Guilherme Blanco
● 10+ anos como desenvolvedor
● Evangelista Open Source
● Trabalha para Yahoo!
● Contribui para Doctrine, Zend Framework, Symfony e
PHP
● No Twitter: @guilhermeblanco
● No GitHub: http://github.com/guilhermeblanco
3
Dependency Injection no PHP 5.3
Um exemplo real na web
Esta palestra é uma tradução de: Dependency Injection in PHP 5.3
Concedida pelo autor Fabien Potencier
4
Dependency Injection no PHP 5.3
● Na maioria das aplicações web, você precisa
gerenciar as preferências do usuário:
● A linguagem do usuário
● Se o usuário está autenticado ou não
● As credenciais do usuário
● ...
5
Dependency Injection no PHP 5.3
● Isto pode ser feito no objeto User (Usuário):
● setLanguage(), getLanguage()
● setAuthenticated(), getAuthenticated()
● addCredential(), hasCredential()
● ...
6
Dependency Injection no PHP 5.3
● As informações do Usuário precisam ser persistidas
entre requisições HTTP
● Nós usamos sessões em PHP para Storage
(Armazenagem)
7
Dependency Injection no PHP 5.3
<?php
class SessionStorage
{
  function __construct($cookieName = 'PHP_SESS_ID')
  {
    session_name($cookieName);
    session_start();
  }
  function set($key, $value)
  {
    $_SESSION[$key] = $value;
  }
  // ...
}
8
Dependency Injection no PHP 5.3
Muito difícil
de
customizar
Muito fácil
de
usar
<?php
class User
{
  protected $storage;
  function __construct()
  {
    $this­>storage = new SessionStorage();
  }
  function setLanguage($language)
  {
    $this­>storage­>set('language', $language);
  }
  // ...
}
$user = new User();
9
Dependency Injection no PHP 5.3
Muito fácil
de
customizar
Um pouco
mais difícil
de usar
<?php
class User
{
  protected $storage;
  function __construct($storage)
  {
    $this­>storage = $storage;
  }
} 
$storage = new SessionStorage();
$user = new User($storage);
10
Dependency Injection no PHP 5.3
● Isto é Dependency Injection (Injeção de Dependência)
● Nada além disso...
11
Dependency Injection no PHP 5.3
● Vamos entender porque o primeiro exemplo não é
uma boa idéia...
● Quero mudar o nome do cookie da sessão do usuário
12
Dependency Injection no PHP 5.3
Hardcode
na classe
do Usuário
<?php
class User
{
  protected $storage;
  function __construct()
  {
    $this­>storage = new SessionStorage('SESSION_ID');
  }
  function setLanguage($language)
  {
    $this­>storage­>set('language', $language);
  }
  // ...
}
$user = new User();
13
Dependency Injection no PHP 5.3
Adicionar
uma variável
global?
<?php
class User
{
  protected $storage;
  function __construct()
  {
    $this­>storage = new SessionStorage(STORAGE_SESSION_NAME);
  }
}
define('STORAGE_SESSION_NAME', 'SESSION_ID');
$user = new User();
14
Dependency Injection no PHP 5.3
Configurar
via
Usuário?
<?php
class User
{
  protected $storage;
  function __construct($sessionName)
  {
    $this­>storage = new SessionStorage($sessionName);
  }
}
$user = new User('SESSION_ID');
15
Dependency Injection no PHP 5.3
Configurar
com um
Array?
<?php
class User
{
  protected $storage;
  function __construct($storageOptions)
  {
    $this­>storage = new SessionStorage($storageOptions['session_name']);
  }
}
$user = new User(array('session_name' => 'SESSION_ID'));
16
Dependency Injection no PHP 5.3
● Eu quero mudar a implementação de armazenamento
da sessão
● Sistema de Arquivos
● MySQL
● Memcached
● etc
17
Usar uma
instância no
Registro global?
<?php
class User
{
  protected $storage;
  function __construct()
  {
    $this­>storage = Registry::get('session_storage');
  }
}
$storage = new SessionStorage();
Registry::set('session_storage', $storage);
$user = new User();
Dependency Injection no PHP 5.3
18
Agora, o Usuário (User) depende do Registro
Dependency Injection no PHP 5.3
19
Dependency Injection no PHP 5.3
● Ao invés da dependência do Storage estar
“hardcoded” no construtor da classe Usuário
● Injete a dependência de Storage no objeto Usuário
20
Dependency Injection no PHP 5.3
<?php
class User
{
  protected $storage;
  function __construct($storage)
  {
    $this­>storage = $storage;
  }
}
$storage = new SessionStorage('SESSION_ID');
$user = new User($storage);
21
Dependency Injection no PHP 5.3
Quais as vantagens?
22
Dependency Injection no PHP 5.3
Usar uma estratégia de Storage diferente
23
Uso de uma
estratégia diferente
de Storage
Dependency Injection no PHP 5.3
<?php
class User
{
  protected $storage;
  function __construct($storage)
  {
    $this­>storage = $storage;
  }
}
$storage = new MySQLSessionStorage('SESSION_ID');
$user = new User($storage);
24
Dependency Injection no PHP 5.3
A configuração fica natural
25
A configuração
fica natural
<?php
class User
{
  protected $storage;
  function __construct($storage)
  {
    $this­>storage = $storage;
  }
}
$storage = new MySQLSessionStorage('SESSION_ID');
$user = new User($storage);
Dependency Injection no PHP 5.3
26
Dependency Injection no PHP 5.3
Engloba classes de terceiros (Adapter/Interface)
27
Adiciona
uma interface
Dependency Injection no PHP 5.3
<?php
class User
{
  protected $storage;
  function __construct(SessionStorageInterface $storage)
  {
    $this­>storage = $storage;
  }
}
interface SessionStorageInterface
{
  function get($key);
  function set($key, $value);
}
28
Dependency Injection no PHP 5.3
Mock do objeto Storage (para testes)
29
Dependency Injection no PHP 5.3
Mock de uma
Session
class User
{
  protected $storage;
  function __construct(SessionStorageInterface $storage)
  {
    $this­>storage = $storage;
  }
}
class SessionStorageForTests implements SessionStorageInterface
{
  protected $data = array();
  public function set($key, $value)
  {
    $this­>data[$key] = $value;
  }
  public function get($key)
  {
    return $this­>data[$key];
  }
}
30
Dependency Injection no PHP 5.3
● Uso de diferentes estratégias de Storage
● Configuração fica natural
● Engloba classes de terceiros (Adapter/Interface)
● Mock do objeto Storage (para testes)
● Fácil sem alterar a classe Usuário (User)
31
Dependency Injection no PHP 5.3
“Dependency Injection é onde os objetos obtém
suas dependências através do construtor,
métodos ou diretamente nas propriedades”
http://www.picocontainer.org/injection.html
32
Dependency Injection no PHP 5.3
<?php
$storage = new SessionStorage();
// constructor injection
$user = new User($storage);
// setter injection
$user = new User();
$user­>setStorage($storage);
// property injection
$user = new User();
$user­>storage = $storage;
33
Dependency Injection no PHP 5.3
Um exemplo web um pouco mais complexo
34
Dependency Injection no PHP 5.3
<?php
$request = new Request();
$response = new Response();
$storage = new FileSessionStorage('SESSION_ID');
$user = new User($storage);
$cache = new FileCache(
  array('dir' => dirname(__FILE__) . '/cache')
);
$routing = new Routing($cache);
35
Dependency Injection no PHP 5.3
<?php
class Application
{
  function __construct()
  {
    $this­>request = new WebRequest();
    $this­>response = new WebResponse();
    $storage = new FileSessionStorage('SESSION_ID');
    $this­>user = new User($storage);
    $cache = new FileCache(
      array('dir' => dirname(__FILE__).'/cache')
    );
    $this­>routing = new Routing($cache);
  }
}
$application = new Application();
36
Dependency Injection no PHP 5.3
De volta à estaca zero
37
Dependency Injection no PHP 5.3
<?php
class Application
{
  function __construct()
  {
    $this­>request = new WebRequest();
    $this­>response = new WebResponse();
    $storage = new FileSessionStorage('SESSION_ID');
    $this­>user = new User($storage);
    $cache = new FileCache(
      array('dir' => dirname(__FILE__).'/cache')
    );
    $this­>routing = new Routing($cache);
  }
}
$application = new Application();
38
Dependency Injection no PHP 5.3
● Nós precisamos de um Container
● Descreve objetos e suas dependências
● Instancia e configura objetos sob demanda
39
Dependency Injection no PHP 5.3
● Um Container DEVE ser capaz de gerenciar
QUALQUER objeto PHP (POPO)
● Os objetos NÃO DEVEM saber que são gerenciados
por um Container
40
Dependency Injection no PHP 5.3
● Parâmetros
● A implementação de SessionStorageInterface que
queremos usar (o nome da classe)
● O nome da sessão
● Objetos
● SessionStorage
● User
● Dependências
● Usuário depende de uma implementação de
SessionStorageInterface
41
Dependency Injection no PHP 5.3
Vamos criar um simples Container com o PHP 5.3
42
Dependency Injection no PHP 5.3
DIC (Dependency Injection Container)
Gerenciando parâmetros
43
Dependency Injection no PHP 5.3
<?php
class Container
{
  protected $parameters = array();
  public function setParameter($key, $value)
  {
    $this­>parameters[$key] = $value;
  }
  public function getParameter($key)
  {
    return $this­>parameters[$key];
  }
}
44
<?php
$class = $container­>getParameter('storage_class');
$sessionStorage = new $class($container­>getParameter('session_name'));
$user = new User($sessionStorage);
<?php
$container = new Container();
$container­>setParameter('session_name', 'SESSION_ID');
$container­>setParameter('storage_class', 'SessionStorage');
Dependency Injection no PHP 5.3
Criação de Objeto
Customização
Desacoplamento
45
Dependency Injection no PHP 5.3
<?php
class Container
{
  protected $parameters = array();
  public function __set($key, $value)
  {
    $this­>parameters[$key] = $value;
  }
  public function __get($key)
  {
    return $this­>parameters[$key];
  }
}
46
Dependency Injection no PHP 5.3
<?php
$container = new Container();
$container­>session_name = 'SESSION_ID';
$container­>storage_class = 'SessionStorage';
$sessionStorage = new $container­>storage_class($container­>session_name);
$user = new User($sessionStorage);
Interface é
mais limpa
47
Dependency Injection no PHP 5.3
DIC (Dependency Injection Container)
Gerenciando objetos
48
Dependency Injection no PHP 5.3
● Precisamos de uma forma para descrever como criar
objetos, sem na realidade instanciar qualquer coisa!
● Funções anônimas existem para nos salvar!
49
Funções anônimas / Lambdas
● Função anônima é uma função definida diretamente e
sem um nome
<?php
function () { echo 'Hello World'; };
50
Funções anônimas / Lambdas
● Uma lambda pode ser armazenado em uma variável
<?php
$hello = function () { echo 'Hello World'; };
51
Funções anônimas / Lambdas
● E depois podem ser usadas como qualquer
executável PHP
<?php
$hello();
call_user_func($hello);
52
Funções anônimas / Lambdas
● Você também pode passar uma lambda como um
argumento de uma função ou método
<?php
function foo(Closure $func)
{
  $func();
}
foo($hello);
53
Funções anônimas / Lambdas
<?php
$hello = function ($name) { echo 'Hello '.$name; };
$hello('Fabien');
call_user_func($hello, 'Fabien');
function foo(Closure $func, $name)
{
  $func($name);
}
foo($hello, 'Fabien');
54
Dependency Injection no PHP 5.3
DIC (Dependency Injection Container)
Gerenciando objetos
55
Armazene um lambda
capaz de criar objetos
sob demanda
Dependency Injection no PHP 5.3
Notifique a closure
para criar um objeto
passando um Container
class Container
{
  protected $parameters = array();
  protected $objects = array();
  public function __set($key, $value)
  {
    $this­>parameters[$key] = $value;
  }
  public function __get($key)
  {
    return $this­>parameters[$key];
  }
  public function setService($key, Closure $service)
  {
    $this­>objects[$key] = $service;
  }
  public function getService($key)
  {
    return $this­>objects[$key]($this);
  }
}
56
Dependency Injection no PHP 5.3
<?php
$container = new Container();
$container­>session_name = 'SESSION_ID';
$container­>storage_class = 'SessionStorage';
$container­>setService('user', function ($c)
{
  return new User($c­>getService('storage'));
});
$container­>setService('storage', function ($c)
{
  return new $c­>storage_class($c­>session_name);
});
<?php
$user = $container­>getService('user');
57
Dependency Injection no PHP 5.3
Simplificando o código
58
Dependency Injection no PHP 5.3
<?php
class Container
{
  protected $values = array();
  function __set($id, $value)
  {
    $this­>values[$id] = $value;
  }
  function __get($id)
  {
    if (is_callable($this­>values[$id]))
    {
      return $this­>values[$id]($this);
    }
    else
    {
      return $this­>values[$id];
    }
  }
}
59
Dependency Injection no PHP 5.3
<?php
$container = new Container();
$container­>session_name = 'SESSION_ID';
$container­>storage_class = 'SessionStorage';
$container­>user = function ($c)
{
  return new User($c­>storage);
};
$container­>storage = function ($c)
{
  return new $c­>storage_class($c­>session_name);
};
Interface unificada
60
Dependency Injection no PHP 5.3
DIC (Dependency Injection Container)
Escopo
61
Dependency Injection no PHP 5.3
● Para alguns tipos de objetos, como o Usuário, o
Container sempre deve retornar a mesma instância
<?php
spl_object_hash($container­>user) !== spl_object_hash($container­>user);
62
Dependency Injection no PHP 5.3
<?php
$container­>user = function ($c)
{
  static $user;
  if (is_null($user))
  {
    $user = new User($c­>storage);
  }
  return $user;
};
63
Dependency Injection no PHP 5.3
<?php
spl_object_hash($container­>user) === spl_object_hash($container­>user);
64
Dependency Injection no PHP 5.3
<?php
$container­>user = $container­>asShared(function ($c)
{
  return new User($c­>storage);
});
65
Dependency Injection no PHP 5.3
Uma Closure é uma lambda que lembra seu
estado durante sua criação
66
Dependency Injection no PHP 5.3
<?php
class Article
{
  public function __construct($title)
  {
    $this­>title = $title;
  }
  public function getTitle()
  {
    return $this­>title;
  }
}
$articles = array(
  new Article('Title 1'),
  new Article('Title 2'),
);
67
Dependency Injection no PHP 5.3
<?php
$mapper = function ($article)
{
  return $article­>getTitle();
};
$titles = array_map($mapper, $articles);
68
Dependency Injection no PHP 5.3
<?php
$method = 'getTitle';
$mapper = function ($article) use($method)
{
  return $article­>$method();
};
$method = 'getAuthor';
$titles = array_map($mapper, $articles);
69
Dependency Injection no PHP 5.3
<?php
$mapper = function ($method)
{
  return function ($article) use ($method)
  {
    return $article­>$method();
  };
};
70
Dependency Injection no PHP 5.3
<?php
$titles = array_map($mapper('getTitle'), $articles);
$authors = array_map($mapper('getAuthor'), $articles);
71
Dependency Injection no PHP 5.3
<?php
$container­>user = $container­>asShared(function ($c)
{
  return new User($c­>storage);
});
72
Dependency Injection no PHP 5.3
<?php
function asShared(Closure $lambda)
{
  return function ($container) use ($lambda)
  {
    static $object;
    if (is_null($object))
    {
      $object = $lambda($container);
    }
    return $object;
  };
}
73
Dependency Injection no PHP 5.3
Gerenciamento
de erros
class Container
{
  protected $values = array();
  function __set($id, $value) {
    $this­>values[$id] = $value;
  }
  function __get($id) {
    if ( ! isset($this­>values[$id])) {
      throw new InvalidArgumentException(sprintf('Value "%s" is not defined.', $id));
    }
    if (is_callable($this­>values[$id])) {
      return $this­>values[$id]($this);
    } else {
      return $this­>values[$id];
    }
  }
  function asShared($callable) {
    return function ($c) use ($callable) {
      static $object;
      if (is_null($object)) {
        $object = $callable($c);
      }
      return $object;
    };
  }
}
74
Dependency Injection no PHP 5.3
NÃO estou afirmando para usarem lambdas em
todos os lugares
Esta apresentação tem o intuito de mostrar como
elas funcionam em exemplos práticos
75
Dependency Injection no PHP 5.3
Um DI Container NÃO gerencia
TODOS seus objetos
76
Dependency Injection no PHP 5.3
Boa regra para lembrar:
Ele gerencia objetos “globais”
Objetos com somente uma instância (!=
singleton)
77
Dependency Injection no PHP 5.3
COMO
Um Usuário, uma Requisição (Request), um
Logger, uma conexão com a Base de Dados, ...
78
Dependency Injection no PHP 5.3
E NÃO COMO
Objetos de Modelo (um Blog, um Produto, ...)
79
Dependency Injection no PHP 5.3
Lembre-se: Na maioria das vezes,
você não precisa de um Container para usar
Dependency Injection
80
Dependency Injection no PHP 5.3
Você pode começar a usar e se beneficiar de
Dependency Injection hoje
81
Dependency Injection no PHP 5.3
Implementando uma no seu projeto
Usando bibliotecas externas que já utilizam DI
sem precisa de um Container
82
Dependency Injection no PHP 5.3
Symfony
Zend Framework
Doctrine
ezComponents
Swift Mailer
...
83
Dependency Injection no PHP 5.3
● Symfony Components DependencyInjection
● Usado no core do Symfony 2 (uma das mais rápidas
frameworks)
● Flexível (YAML, XML, INI and PHP)
84
Perguntas?

Dependency injection

  • 1.
    Dependency Injection noPHP 5.3 Guilherme Blanco – Yahoo!
  • 2.
    2 Guilherme Blanco ● 10+anos como desenvolvedor ● Evangelista Open Source ● Trabalha para Yahoo! ● Contribui para Doctrine, Zend Framework, Symfony e PHP ● No Twitter: @guilhermeblanco ● No GitHub: http://github.com/guilhermeblanco
  • 3.
    3 Dependency Injection noPHP 5.3 Um exemplo real na web Esta palestra é uma tradução de: Dependency Injection in PHP 5.3 Concedida pelo autor Fabien Potencier
  • 4.
    4 Dependency Injection noPHP 5.3 ● Na maioria das aplicações web, você precisa gerenciar as preferências do usuário: ● A linguagem do usuário ● Se o usuário está autenticado ou não ● As credenciais do usuário ● ...
  • 5.
    5 Dependency Injection noPHP 5.3 ● Isto pode ser feito no objeto User (Usuário): ● setLanguage(), getLanguage() ● setAuthenticated(), getAuthenticated() ● addCredential(), hasCredential() ● ...
  • 6.
    6 Dependency Injection noPHP 5.3 ● As informações do Usuário precisam ser persistidas entre requisições HTTP ● Nós usamos sessões em PHP para Storage (Armazenagem)
  • 7.
    7 Dependency Injection noPHP 5.3 <?php class SessionStorage {   function __construct($cookieName = 'PHP_SESS_ID')   {     session_name($cookieName);     session_start();   }   function set($key, $value)   {     $_SESSION[$key] = $value;   }   // ... }
  • 8.
    8 Dependency Injection noPHP 5.3 Muito difícil de customizar Muito fácil de usar <?php class User {   protected $storage;   function __construct()   {     $this­>storage = new SessionStorage();   }   function setLanguage($language)   {     $this­>storage­>set('language', $language);   }   // ... } $user = new User();
  • 9.
    9 Dependency Injection noPHP 5.3 Muito fácil de customizar Um pouco mais difícil de usar <?php class User {   protected $storage;   function __construct($storage)   {     $this­>storage = $storage;   } }  $storage = new SessionStorage(); $user = new User($storage);
  • 10.
    10 Dependency Injection noPHP 5.3 ● Isto é Dependency Injection (Injeção de Dependência) ● Nada além disso...
  • 11.
    11 Dependency Injection noPHP 5.3 ● Vamos entender porque o primeiro exemplo não é uma boa idéia... ● Quero mudar o nome do cookie da sessão do usuário
  • 12.
    12 Dependency Injection noPHP 5.3 Hardcode na classe do Usuário <?php class User {   protected $storage;   function __construct()   {     $this­>storage = new SessionStorage('SESSION_ID');   }   function setLanguage($language)   {     $this­>storage­>set('language', $language);   }   // ... } $user = new User();
  • 13.
    13 Dependency Injection noPHP 5.3 Adicionar uma variável global? <?php class User {   protected $storage;   function __construct()   {     $this­>storage = new SessionStorage(STORAGE_SESSION_NAME);   } } define('STORAGE_SESSION_NAME', 'SESSION_ID'); $user = new User();
  • 14.
    14 Dependency Injection noPHP 5.3 Configurar via Usuário? <?php class User {   protected $storage;   function __construct($sessionName)   {     $this­>storage = new SessionStorage($sessionName);   } } $user = new User('SESSION_ID');
  • 15.
    15 Dependency Injection noPHP 5.3 Configurar com um Array? <?php class User {   protected $storage;   function __construct($storageOptions)   {     $this­>storage = new SessionStorage($storageOptions['session_name']);   } } $user = new User(array('session_name' => 'SESSION_ID'));
  • 16.
    16 Dependency Injection noPHP 5.3 ● Eu quero mudar a implementação de armazenamento da sessão ● Sistema de Arquivos ● MySQL ● Memcached ● etc
  • 17.
    17 Usar uma instância no Registroglobal? <?php class User {   protected $storage;   function __construct()   {     $this­>storage = Registry::get('session_storage');   } } $storage = new SessionStorage(); Registry::set('session_storage', $storage); $user = new User(); Dependency Injection no PHP 5.3
  • 18.
    18 Agora, o Usuário(User) depende do Registro Dependency Injection no PHP 5.3
  • 19.
    19 Dependency Injection noPHP 5.3 ● Ao invés da dependência do Storage estar “hardcoded” no construtor da classe Usuário ● Injete a dependência de Storage no objeto Usuário
  • 20.
    20 Dependency Injection noPHP 5.3 <?php class User {   protected $storage;   function __construct($storage)   {     $this­>storage = $storage;   } } $storage = new SessionStorage('SESSION_ID'); $user = new User($storage);
  • 21.
    21 Dependency Injection noPHP 5.3 Quais as vantagens?
  • 22.
    22 Dependency Injection noPHP 5.3 Usar uma estratégia de Storage diferente
  • 23.
    23 Uso de uma estratégiadiferente de Storage Dependency Injection no PHP 5.3 <?php class User {   protected $storage;   function __construct($storage)   {     $this­>storage = $storage;   } } $storage = new MySQLSessionStorage('SESSION_ID'); $user = new User($storage);
  • 24.
    24 Dependency Injection noPHP 5.3 A configuração fica natural
  • 25.
  • 26.
    26 Dependency Injection noPHP 5.3 Engloba classes de terceiros (Adapter/Interface)
  • 27.
    27 Adiciona uma interface Dependency Injectionno PHP 5.3 <?php class User {   protected $storage;   function __construct(SessionStorageInterface $storage)   {     $this­>storage = $storage;   } } interface SessionStorageInterface {   function get($key);   function set($key, $value); }
  • 28.
    28 Dependency Injection noPHP 5.3 Mock do objeto Storage (para testes)
  • 29.
    29 Dependency Injection noPHP 5.3 Mock de uma Session class User {   protected $storage;   function __construct(SessionStorageInterface $storage)   {     $this­>storage = $storage;   } } class SessionStorageForTests implements SessionStorageInterface {   protected $data = array();   public function set($key, $value)   {     $this­>data[$key] = $value;   }   public function get($key)   {     return $this­>data[$key];   } }
  • 30.
    30 Dependency Injection noPHP 5.3 ● Uso de diferentes estratégias de Storage ● Configuração fica natural ● Engloba classes de terceiros (Adapter/Interface) ● Mock do objeto Storage (para testes) ● Fácil sem alterar a classe Usuário (User)
  • 31.
    31 Dependency Injection noPHP 5.3 “Dependency Injection é onde os objetos obtém suas dependências através do construtor, métodos ou diretamente nas propriedades” http://www.picocontainer.org/injection.html
  • 32.
    32 Dependency Injection noPHP 5.3 <?php $storage = new SessionStorage(); // constructor injection $user = new User($storage); // setter injection $user = new User(); $user­>setStorage($storage); // property injection $user = new User(); $user­>storage = $storage;
  • 33.
    33 Dependency Injection noPHP 5.3 Um exemplo web um pouco mais complexo
  • 34.
    34 Dependency Injection noPHP 5.3 <?php $request = new Request(); $response = new Response(); $storage = new FileSessionStorage('SESSION_ID'); $user = new User($storage); $cache = new FileCache(   array('dir' => dirname(__FILE__) . '/cache') ); $routing = new Routing($cache);
  • 35.
    35 Dependency Injection noPHP 5.3 <?php class Application {   function __construct()   {     $this­>request = new WebRequest();     $this­>response = new WebResponse();     $storage = new FileSessionStorage('SESSION_ID');     $this­>user = new User($storage);     $cache = new FileCache(       array('dir' => dirname(__FILE__).'/cache')     );     $this­>routing = new Routing($cache);   } } $application = new Application();
  • 36.
    36 Dependency Injection noPHP 5.3 De volta à estaca zero
  • 37.
    37 Dependency Injection noPHP 5.3 <?php class Application {   function __construct()   {     $this­>request = new WebRequest();     $this­>response = new WebResponse();     $storage = new FileSessionStorage('SESSION_ID');     $this­>user = new User($storage);     $cache = new FileCache(       array('dir' => dirname(__FILE__).'/cache')     );     $this­>routing = new Routing($cache);   } } $application = new Application();
  • 38.
    38 Dependency Injection noPHP 5.3 ● Nós precisamos de um Container ● Descreve objetos e suas dependências ● Instancia e configura objetos sob demanda
  • 39.
    39 Dependency Injection noPHP 5.3 ● Um Container DEVE ser capaz de gerenciar QUALQUER objeto PHP (POPO) ● Os objetos NÃO DEVEM saber que são gerenciados por um Container
  • 40.
    40 Dependency Injection noPHP 5.3 ● Parâmetros ● A implementação de SessionStorageInterface que queremos usar (o nome da classe) ● O nome da sessão ● Objetos ● SessionStorage ● User ● Dependências ● Usuário depende de uma implementação de SessionStorageInterface
  • 41.
    41 Dependency Injection noPHP 5.3 Vamos criar um simples Container com o PHP 5.3
  • 42.
    42 Dependency Injection noPHP 5.3 DIC (Dependency Injection Container) Gerenciando parâmetros
  • 43.
    43 Dependency Injection noPHP 5.3 <?php class Container {   protected $parameters = array();   public function setParameter($key, $value)   {     $this­>parameters[$key] = $value;   }   public function getParameter($key)   {     return $this­>parameters[$key];   } }
  • 44.
  • 45.
    45 Dependency Injection noPHP 5.3 <?php class Container {   protected $parameters = array();   public function __set($key, $value)   {     $this­>parameters[$key] = $value;   }   public function __get($key)   {     return $this­>parameters[$key];   } }
  • 46.
    46 Dependency Injection noPHP 5.3 <?php $container = new Container(); $container­>session_name = 'SESSION_ID'; $container­>storage_class = 'SessionStorage'; $sessionStorage = new $container­>storage_class($container­>session_name); $user = new User($sessionStorage); Interface é mais limpa
  • 47.
    47 Dependency Injection noPHP 5.3 DIC (Dependency Injection Container) Gerenciando objetos
  • 48.
    48 Dependency Injection noPHP 5.3 ● Precisamos de uma forma para descrever como criar objetos, sem na realidade instanciar qualquer coisa! ● Funções anônimas existem para nos salvar!
  • 49.
    49 Funções anônimas /Lambdas ● Função anônima é uma função definida diretamente e sem um nome <?php function () { echo 'Hello World'; };
  • 50.
    50 Funções anônimas /Lambdas ● Uma lambda pode ser armazenado em uma variável <?php $hello = function () { echo 'Hello World'; };
  • 51.
    51 Funções anônimas /Lambdas ● E depois podem ser usadas como qualquer executável PHP <?php $hello(); call_user_func($hello);
  • 52.
    52 Funções anônimas /Lambdas ● Você também pode passar uma lambda como um argumento de uma função ou método <?php function foo(Closure $func) {   $func(); } foo($hello);
  • 53.
    53 Funções anônimas /Lambdas <?php $hello = function ($name) { echo 'Hello '.$name; }; $hello('Fabien'); call_user_func($hello, 'Fabien'); function foo(Closure $func, $name) {   $func($name); } foo($hello, 'Fabien');
  • 54.
    54 Dependency Injection noPHP 5.3 DIC (Dependency Injection Container) Gerenciando objetos
  • 55.
    55 Armazene um lambda capazde criar objetos sob demanda Dependency Injection no PHP 5.3 Notifique a closure para criar um objeto passando um Container class Container {   protected $parameters = array();   protected $objects = array();   public function __set($key, $value)   {     $this­>parameters[$key] = $value;   }   public function __get($key)   {     return $this­>parameters[$key];   }   public function setService($key, Closure $service)   {     $this­>objects[$key] = $service;   }   public function getService($key)   {     return $this­>objects[$key]($this);   } }
  • 56.
    56 Dependency Injection noPHP 5.3 <?php $container = new Container(); $container­>session_name = 'SESSION_ID'; $container­>storage_class = 'SessionStorage'; $container­>setService('user', function ($c) {   return new User($c­>getService('storage')); }); $container­>setService('storage', function ($c) {   return new $c­>storage_class($c­>session_name); }); <?php $user = $container­>getService('user');
  • 57.
    57 Dependency Injection noPHP 5.3 Simplificando o código
  • 58.
    58 Dependency Injection noPHP 5.3 <?php class Container {   protected $values = array();   function __set($id, $value)   {     $this­>values[$id] = $value;   }   function __get($id)   {     if (is_callable($this­>values[$id]))     {       return $this­>values[$id]($this);     }     else     {       return $this­>values[$id];     }   } }
  • 59.
    59 Dependency Injection noPHP 5.3 <?php $container = new Container(); $container­>session_name = 'SESSION_ID'; $container­>storage_class = 'SessionStorage'; $container­>user = function ($c) {   return new User($c­>storage); }; $container­>storage = function ($c) {   return new $c­>storage_class($c­>session_name); }; Interface unificada
  • 60.
    60 Dependency Injection noPHP 5.3 DIC (Dependency Injection Container) Escopo
  • 61.
    61 Dependency Injection noPHP 5.3 ● Para alguns tipos de objetos, como o Usuário, o Container sempre deve retornar a mesma instância <?php spl_object_hash($container­>user) !== spl_object_hash($container­>user);
  • 62.
    62 Dependency Injection noPHP 5.3 <?php $container­>user = function ($c) {   static $user;   if (is_null($user))   {     $user = new User($c­>storage);   }   return $user; };
  • 63.
    63 Dependency Injection noPHP 5.3 <?php spl_object_hash($container­>user) === spl_object_hash($container­>user);
  • 64.
    64 Dependency Injection noPHP 5.3 <?php $container­>user = $container­>asShared(function ($c) {   return new User($c­>storage); });
  • 65.
    65 Dependency Injection noPHP 5.3 Uma Closure é uma lambda que lembra seu estado durante sua criação
  • 66.
    66 Dependency Injection noPHP 5.3 <?php class Article {   public function __construct($title)   {     $this­>title = $title;   }   public function getTitle()   {     return $this­>title;   } } $articles = array(   new Article('Title 1'),   new Article('Title 2'), );
  • 67.
    67 Dependency Injection noPHP 5.3 <?php $mapper = function ($article) {   return $article­>getTitle(); }; $titles = array_map($mapper, $articles);
  • 68.
    68 Dependency Injection noPHP 5.3 <?php $method = 'getTitle'; $mapper = function ($article) use($method) {   return $article­>$method(); }; $method = 'getAuthor'; $titles = array_map($mapper, $articles);
  • 69.
    69 Dependency Injection noPHP 5.3 <?php $mapper = function ($method) {   return function ($article) use ($method)   {     return $article­>$method();   }; };
  • 70.
    70 Dependency Injection noPHP 5.3 <?php $titles = array_map($mapper('getTitle'), $articles); $authors = array_map($mapper('getAuthor'), $articles);
  • 71.
    71 Dependency Injection noPHP 5.3 <?php $container­>user = $container­>asShared(function ($c) {   return new User($c­>storage); });
  • 72.
    72 Dependency Injection noPHP 5.3 <?php function asShared(Closure $lambda) {   return function ($container) use ($lambda)   {     static $object;     if (is_null($object))     {       $object = $lambda($container);     }     return $object;   }; }
  • 73.
    73 Dependency Injection noPHP 5.3 Gerenciamento de erros class Container {   protected $values = array();   function __set($id, $value) {     $this­>values[$id] = $value;   }   function __get($id) {     if ( ! isset($this­>values[$id])) {       throw new InvalidArgumentException(sprintf('Value "%s" is not defined.', $id));     }     if (is_callable($this­>values[$id])) {       return $this­>values[$id]($this);     } else {       return $this­>values[$id];     }   }   function asShared($callable) {     return function ($c) use ($callable) {       static $object;       if (is_null($object)) {         $object = $callable($c);       }       return $object;     };   } }
  • 74.
    74 Dependency Injection noPHP 5.3 NÃO estou afirmando para usarem lambdas em todos os lugares Esta apresentação tem o intuito de mostrar como elas funcionam em exemplos práticos
  • 75.
    75 Dependency Injection noPHP 5.3 Um DI Container NÃO gerencia TODOS seus objetos
  • 76.
    76 Dependency Injection noPHP 5.3 Boa regra para lembrar: Ele gerencia objetos “globais” Objetos com somente uma instância (!= singleton)
  • 77.
    77 Dependency Injection noPHP 5.3 COMO Um Usuário, uma Requisição (Request), um Logger, uma conexão com a Base de Dados, ...
  • 78.
    78 Dependency Injection noPHP 5.3 E NÃO COMO Objetos de Modelo (um Blog, um Produto, ...)
  • 79.
    79 Dependency Injection noPHP 5.3 Lembre-se: Na maioria das vezes, você não precisa de um Container para usar Dependency Injection
  • 80.
    80 Dependency Injection noPHP 5.3 Você pode começar a usar e se beneficiar de Dependency Injection hoje
  • 81.
    81 Dependency Injection noPHP 5.3 Implementando uma no seu projeto Usando bibliotecas externas que já utilizam DI sem precisa de um Container
  • 82.
    82 Dependency Injection noPHP 5.3 Symfony Zend Framework Doctrine ezComponents Swift Mailer ...
  • 83.
    83 Dependency Injection noPHP 5.3 ● Symfony Components DependencyInjection ● Usado no core do Symfony 2 (uma das mais rápidas frameworks) ● Flexível (YAML, XML, INI and PHP)
  • 84.