Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Design Patterns com PHP

1,479 views

Published on

Palestra sobre utilização de design patterns em PHP. Exemplos práticos com Singleton, Facade, Adapter, Front Controller, Template View, Table Data Gateway e Active Record.

Published in: Technology

Design Patterns com PHP

  1. 1. Design Patterns com PHP Conceitos, exemplos, e outras coisas Pablo Dall'Oglio @pablodalloglio fb/pablodalloglio
  2. 2. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #2 Meu caminho ● Clipper (1994-1998): comercial, bibliotecas, funções; ● Delphi (1998-1999): automação, componentes; ● PHP (2000): SAGU (php+html+sql); ● PHP-GTK(2001): PHP só com classes; ● Agata Report (2001-2006); ● Gnuteca (2002): PHP Web com classes; ● PHP-GTK: Criando Aplicações Gráficas com PHP (2004); ● Design Patterns (2004): Unisinos; ● Core (2006): Primeira experiência com Framework MVC; ● PHP: Programando com Orientação a Objetos (2007); ● Mestrado em Engenharia de Software (2008, 2009); ● Criando Relatórios com PHP (2011); ● Adianti Framework para PHP (2012).
  3. 3. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #3 O que são padrões? Existem padrões na diversidade Jargão próprio
  4. 4. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #4 O que são padrões? A aplicação do padrão depende do contexto
  5. 5. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #5 Design Pattern O que são Design Patterns ? “Um Pattern descreve um problema que ocorre com frequência em nosso ambiente, e então explica a essência da solução para este problema, de forma que tal solução possa ser utilizada milhões de outras vezes...” Christopher Alexander (1936 arquiteto) Datas importantes: ● 1977 Christopher o aplica na área da Arquitetura; ● 1987 Kent Beck/Ward Cunningham programação;→ ● 1994 Design Patterns: Elements of Reusable OO Software; ● 2002 Patterns of Enterprise Application Architecture.
  6. 6. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #6 Design Patterns ● Padrões são descobertos, não inventados; ● Na maioria das vezes, já utilizamos algum padrão, sem saber; ● O conhecimento dos padrões nos leva a distinguir em quais situações utilizá-los; ● Não existe padrão melhor ou pior, existem padrões que são mais indicados para determinadas situações; ● Um padrão não é uma solução pronta; ● Os códigos a seguir são apenas UMA das formas de implementar os patterns, provavelmente não a melhor, visto que aqui o enfoque é DIDÁTICO :-)
  7. 7. Padrões GoF
  8. 8. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #8 ● É necessário compartilhar informações (prefs, configs); ● Visíveis dentro de diferentes contextos, classes, métodos; ● Variáveis globais, são do mal, falta encapsulamento; ● Como compartilhar uma única versão da verdade; ● Singleton: ● Classe é visível global; ● Mas permite N Objetos; ● E se retornasse o mesmo? ● Limitar a instanciação; ● Método para criar 1 Obj; ● Não mais do que 1. Singleton
  9. 9. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #9 ● Como fabricar apenas uma instância? ● Seu método construtor é marcado como private; ● Tente dar um new fora da classe terá um: Fatal Error; ● Só poderá instanciar dentro da própria classe; ● É preciso criar outro método de instanciação: getInstance(); ● Retornará sempre a mesma instância. Singleton
  10. 10. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #10 <?php class Preferencias { private $data; private static $instance; private function __construct() { $this->data = parse_ini_file('application.ini'); } public static function getInstance() { if (empty(self::$instance)) { self::$instance = new self; } return self::$instance; } public function setData($key, $value) { $this->data[$key] = $value; } public function getData($key) {} public function save() {} } Singleton Única instância que será criada
  11. 11. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #11 <?php // obtém uma instância $p1 = Preferencias::getInstance(); print 'A linguagem é: '. $p1->getData('language') . "<br>n"; $p1->setData('language', 'pt'); print 'A linguagem é: '. $p1->getData('language') . "<br>n"; <?php // obtém a mesma instância $p2 = Preferencias::getInstance(); print 'A linguagem é: '. $p2->getData('language') . "<br>n"; // Descomentar para gravar o valor // $p1->save(); Singleton
  12. 12. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #12 Acoplamento ● Muitos desenvolvedores integram bibliotecas assim: Alto acoplamento: Até pode funcionar, mas...
  13. 13. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #13 ● É quanto um módulo (classe, método) conhece e depende de outro; ● Baixo: – Não depende de muitas outras; – Menos efeitos colaterais em modificações. ● Alto: – Menos reutilizável sozinha; – Mais sensível à mudanças. ● O objetivo é criar modelos com baixo acoplamento; ● É impossível acoplamento ZERO; Acoplamento
  14. 14. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #14 Facade
  15. 15. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #15 Facade ● Facade ajuda a diminuir o acoplamento; ● Oferece uma interface única para um conjunto de interfaces de um subsistema; ● A APP ficará dependente da Facade, não do subsistema. APP
  16. 16. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #16 Facade <?php if ($paymenttype_id == 1) // PAGSEGURO { $paymentRequest = new PagSeguroPaymentRequest(); $item = new PagSeguroItem; $item->setDescription( $product->description ); $item->setQuantity( $data->amount ); $item->setAmount( $price ); $paymentRequest->addItem($item); $address = new PagSeguroAddress; $address->setPostalCode( $customer->postal ); $address->setStreet( $customer->address ); $address->setCity( $customer->city ); $paymentRequest->setShippingAddress($address); $sender = new PagSeguroSender; $sender->setName( $customer->name ); $sender->setEmail( $customer->email ); $paymentRequest->setSender($sender); }
  17. 17. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #17 Facade <?php else if ($paymenttype_id == 2) // PAYPAL { $total = ($product->price * $data->amount); // dados para enviar para o paypal $padata ='&CURRENCYCODE='.urlencode($ini['currency']). '&PAYMENTACTION=Sale'. '&ALLOWNOTE=1'. '&PAYMENTREQUEST_0_AMT='.$total. '&PAYMENTREQUEST_0_ITEMAMT='.$total. '&L_PAYMENTREQUEST_0_QTY0='. $data->amount. '&L_PAYMENTREQUEST_0_AMT0='.$product->price. '&L_PAYMENTREQUEST_0_NAME0='.$product->description. '&L_PAYMENTREQUEST_0_NUMBER0='.1. '&AMT='.$total; // obtém o token $paypal= new PayPalFacade; $httpresult = $paypal->PPHttpPost('SetExpressCheckout', $padata, $ini['username'], $ini['password']); } ?>
  18. 18. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #18 Facade <?php class PaymentFacade { public function addItem($desc, $qtde, $preco) { //... } public function setCustomer($nome, $ender, $cidade) { //... } public function setPaymentType($type) { //... } public function process() { //... } } ?> Pode ser resolvido com outros padrões também
  19. 19. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #19 Adapter ● Favorece o isolamento e a manutenção; ● Converte a interface de uma classe em outra; ● Também conhecido como Wrapper: – Object Wrapper: Encapsula adaptado por composição; – Class Wrapper: Adapta interface por herança.
  20. 20. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #20 Adapter <?php class PHPMailerAdapter { private $pm; public function __construct() { $this->pm = new PHPMailer; $this->pm-> CharSet = 'utf-8'; } public function setFrom($from, $name) { $this->pm-> From = $from; $this->pm-> FromName = $name; } public function setTextBody($body) { $this->pm-> Body = $body; $this->pm-> IsHTML(false); } Wrapper por Composição
  21. 21. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #21 Adapter <?php require_once 'PHPMailer.php'; require_once 'classes/PHPMailerAdapter.php'; $mail = new PHPMailerAdapter; $mail->setUseSmtp(); $mail->setSmtpHost('smtp.gmail.com', 465); $mail->setSmtpUser('pablo@dalloglio.net', 'minhasenha'); $mail->setFrom('pablo@dalloglio.net', 'Pablo Dall Oglio'); $mail->addAddress('destinatario@gmail.com', 'Destinatário'); $mail->setSubject('Oi Cara'); $mail->setHtmlBody('<b>Isso é um <i>teste</i></b>'); $mail->send();
  22. 22. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #22 Evolução "... the hardest is evolving reusable object- oriented software We touch on this a little bit in Design Patterns. For example, factories, adapters and facades can help when it comes to changing and evolving a reusable library" Erich Gamma - Gang of Four evoluir
  23. 23. Padrões de Visualização e controle
  24. 24. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #24 #Go Horse 1 <?php // configuração $conn = pg_connect("host=localhost port=5432 dbname=exemplos..."); // query $query = 'SELECT id, nome, endereco FROM cliente WHERE id not in (...)'; // resultados $result = pg_query($conn, $query); if ($result) { // apresentação echo '<table border="1">'; while ($row = pg_fetch_assoc($result)) { echo '<tr>'; echo '<td>' . $row['id'] . '</td>'; echo '<td>' . $row['nome'] . '</td>'; echo '<td>' . $row['endereco'] . '</td>'; echo '</tr>'; } echo '</table>'; } pg_close($conn); Business rule? Apresentação Configuração
  25. 25. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #25 One script per page ● Você começou a programar Web... ● Cada coisa é um script; ● Um script representa um programa; ● Podemos ter vários scripts para o mesmo sistema; ● Listagem a seguir:
  26. 26. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #26 Front Controller ● Um objeto que interpreta uma requisição para uma ação e decide o fluxo de execução a tomar; ● Existem tarefas que se repetem por todas as rotinas (logs, autenticação, internacionalização e padronização de interface); ● A aplicação pode ter um ponto central de acesso, que coordena qual programa será executado; ● O Front Controller é um tipo de script centralizador, também conhecido por “One script serves all”; ● Um Front Controller geralmente é representado por um objeto que recebe todas as requisições de um site; ● A tarefa deste objeto é analisar alguns parâmetros, como a URL e decidir qual comando executar, qual objeto instanciar.
  27. 27. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #27 Front Controller
  28. 28. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #28 Front Controller index.php <?php if ($_GET) { $class = $_GET['class']; if (class_exists($class)) { $pagina = new $class; $pagina->show(); } } Page.php class Page { public function show() { if ($_REQUEST) { $method = $_REQUEST['method']; if (method_exists($this, $method)) { call_user_func(array($this, $method), $_REQUEST); } } } } sessão, permissões, timezone, segurança, layout... Todos precisam ter um método show? Layer Supertype
  29. 29. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #29 Front Controller <?php class CidadeControl extends Page { public function listar() { try { Transaction::open('livro'); $cidades = $cidade->all(); if ($cidades) { foreach ($cidades as $cidade) { print "{$cidade->id} - {$cidade->nome}<br>"; } } Transaction::close(); } catch (Exception $e) { print $e->getMessage(); } } } index.php?class=CidadeControl&method=listar
  30. 30. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #30 Template View ● Você precisa caprichar no Visual; ● Os componentes prontos não são suficientes; ● Não cometa o erro de ecoar HTML do seu Controller; ● Você precisa misturar conteúdo dinâmico e estático; ● Templates permitem separar as coisas (PHP/HTML); ● HTML com pequenas marcações em seu conteúdo; ● Marcações são substituídas por conteúdo dinâmico; ● Permite substituição, repetição; ● Permite isolar chamadas de bibliotecas (jQuery, Bootstrap); ● Quando a biblioteca muda, é necessário atualizá-lo (!SASS, LESS).
  31. 31. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #31 Html Renderer (AF) <!--[main]--> <table class="tform" style="border:1px solid #B7B7B7"> <tr> <td colspan="2">Customer data</div></td> </tr> <tr> <td width="50%"> ID </td> <td width="50%"> {$id} </td> </tr> <tr> <td width="50%"> Name </td> <td width="50%"> {$name} </td> </tr> <tr> <td width="50%"> Address </td> <td width="50%"> {$address} </td> </tr> </table> <!--[/main]--> Replaces
  32. 32. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #32 Html Renderer (AF) app/control/TemplateController.php class TemplateController extends TPage { public function exibe() { $html = new THtmlRenderer('app/resources/customer.html'); TTransaction::open('samples'); $customer = Customer::find(1); $replace = ['code' => $customer->id, 'name' => $customer->name, 'address' => $customer->address]; $html->enableSection('main', $replace); $html->show(); TTransaction::close(); } }
  33. 33. Padrões de persistência
  34. 34. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #34 #Go Horse 2 class ContaReceber { function inserir($id, $a, $b, $c) { $sql = "INSERT INTO conta_receber..."; // exec $sql; } function listar() { $sql = "SELECT * FROM conta_receber"; // exec $sql } function getContasEmAberto() { $sql = "SELECT id, sum(valor) FROM contas_receber cr, lancamentos l WHERE l.conta_id = cr.id GROUP BY 1 HAVING sum(valor) >1”; } function getContasEmAtraso() { $sql = "SELECT ... ... WHERE dt_vencimento <= date(now())"; } } Lógicas complexas extensas em SQL 10 piores SQL.pdf Começou a separar Código reflexo do BD Pensamento estruturado
  35. 35. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #35 Mapeamento Obj-Rel ● BDR surgiram na década 70 (padrão estruturado); ● BDR não suportam diversos conceitos OO (herança, composição, agregação, polimorfismo, métodos, etc); ● BDOO ainda tem pouca adoção (desempenho inferior, pouca documentação, ferramentas não tão maduras); ● BDR são amplamente utilizados para armazenar objetos; ● Há uma dissonância corrigida pelo uso de técnicas MOR; ● Muitas ferramentas de persistência surgiram; ● Persistência significa continuar a existir, perseverar; ● Objetos existirem em um meio externo à aplicação; ● Vamos ver algumas técnicas.
  36. 36. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #36 Table Data Gateway ● Uma classe responsável por persistir (inserir, alterar, excluir) e retornar dados do BD; ● Uma (1) classe por tabela do banco de dados. Apenas uma instância desta classe irá manipular todos os registros; ● Stateless: É necessário sempre identificar o registro sobre o qual o método estará operando;
  37. 37. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #37 Table Data Gateway <?php class ProdutoGateway { private static $conn; public static function setConnection( PDO $conn ) { self::$conn = $conn; } public function find($id, $class = 'stdClass') { $sql = "SELECT * FROM produto where id = '$id' "; $result = self::$conn->query($sql); return $result->fetchObject($class); } public function save($data) { if (empty($data->id)) { $sql = "INSERT INTO produto (descricao, estoque, ...)". " VALUES ('{$id}', '{$data->descricao}', ... )"; } Injeção de dependência Usada pela Model INSERT or UPDATE
  38. 38. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #38 Table Data Gateway <?php class Produto { private $data; function __get($prop) {} function __set($prop, $value) {} public static function find($id) { $gw = new ProdutoGateway; return $gw->find($id, 'Produto'); } public function save() { $gw = new ProdutoGateway; return $gw->save( (object) $this->data); } public function getMargemLucro() {} public function registraCompra($custo, $quantidade) {} } Model Chamada do Gateway Lógica de negócios
  39. 39. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #39 Active Record ● Classe que conjuga lógica e persistência; ● Um (1) objeto por linha do banco de dados; ● Statefull: Retém os dados do objeto corrente.
  40. 40. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #40 Layer Supertype ● Métodos se repetem (load, update, delete, ...); ● Métodos podem ser generalizados se seguirmos convenções; ● Vamos criar uma superclasse para persistência; ● Herdada por todos objetos de negócio; ● Ela implementará métodos de maneira genérica; ● Layer Supertype: Superclasse para uma camada inteira; ● Funcionalidades comuns para todos objetos na superclasse; ● Métodos de NEGÓCIO ficam na classe filha;
  41. 41. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #41 Active Record Armazenar um novo objeto (INSERT). class Pessoa extends TRecord { const TABLENAME = 'tab_pessoas'; const PRIMARYKEY= 'id'; const IDPOLICY = 'max'; // {max, serial} } TTransaction::open('samples'); $object = new Pessoa; $object->name = 'Maria da Silva'; $object->address = 'Rua da Conceicao'; $object->phone = '(51) 8111-2222'; $object->status = 'S'; $object->email = 'maria@email.com'; $object->store(); // armazena o objeto TTransaction::close(); // fecha a transação. Business Rules Supertype Statefull
  42. 42. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #42 Active Record Alterar um objeto já existente (UPDATE). TTransaction::open('samples'); // abre uma transação $customer = Customer::find(31); // carrega o cliente 31 if ($customer) // se existe { $customer->phone = '51 8111-3333'; // muda o fone $customer->store(); // armazena o objeto } new TMessage('info', 'Objeto atualizado'); TTransaction::close(); // fecha a transação. INSERT OR UPDATE STATEFULL
  43. 43. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #43 Atalhos Manipular um conjunto de objetos conforme um filtro. $product = Product::find(2); $products = Product::all(); $count = User::where('age', '>', 18)->count(); $products = Product::where('name', 'like', '%Computer%')->load(); $products = Product::where('id', '>', '1')->orderBy('price')->load(); $products = Product::where('type', '=', '10')->take(10)->skip(20)->load(); User::where('age', '>', 100)->delete(); $contacts = Customer::find(123)->hasMany('Contact'); $turma = Turma::find(10); foreach ($turma->getMatriculas() as $matricula) { print $matricula->aluno->nome; } SQL gerado com Prepared NAVEGABILIDADE entre relações
  44. 44. Adianti Solutions Ltda © Pablo Dall'Oglio Programando para Programadores #44 Obrigado ● Contato: – pablo.blog.br – adianti.com.br – @pablodalloglio – @adiantisolution ● Não esquecer de falar do Sorteio!

×