Você está na página 1de 9

Singleton PHP Exemplos de Padres de Projeto

Padres de Projeto, PHP por Tarcsio

J passou por suas cabeas que em algumas situaes, ns programadores criamos instncias de classes com vida curta ou que gostariamos de ter uma mesma instncia da classe em vrios arquivos ou camadas do cdigo? Ai vocs me perguntam Como assim?. Vou mostrar alguns exemplos de Anti-Padres e como usar o Singleton PHP, assim fica mais claro.

Anti-Padro Singleton PHP


Comumente vejo por ai algumas classes de configurao como a mostrado abaixo. Arquivo Config.php 1 /** 2 * Classe abstrata, me de todas as classes de configurao 3 * @author DigitalDev */ 4 abstract class Config 5 { 6 private $v_params; 7 public function __contruct() 8 { 9 $this->v_params = array(); 10 } 11 12 protected function setParam($mx_param,$mx_value) { 13 $this->v_params[$mx_param] = $mx_value; 14

15 16 17 18 19 20 21 22} 23 24 25 26

return $this; } protected function getParam($mx_param) { if(isset($this->v_params[$mx_param])) return $this->v_params[$mx_param]; return null; }

Arquivo ConfigPrincipal.php 1 2 /** 3 * Classe de configurao principal do sistema 4 * @author DigitalDev 5 */ 6 7 //incluindo o arquivo da classe me require_once 'Config.php'; 8 9 class ConfigPrincipal extends Config 10{ public function __construct() 11 { 12 parent::__contruct(); 13 14 //definindo algumas configuraes 15 $this->setParam('sistema_nome', 'DigitalDev Site'); 16 $this->setParam('adm_nome','Tarcisio Ruas'); $this->setParam('adm_email','contato@digitaldev.com.br'); 17 } 18 } 19 20 Imaginem que seja necessrio acessar os dados da classe de configurao principal em alguns lugares do cdigo, por exemplo o arquivo index.php, onde colocaremos as tags HTML head e title do sistema. 1 <?php 2 //incluindo o arquivo de configurao principal require_once 'ConfigPrincipal.php'; 3 4 //instanciando a classe de configurao 5 $o_config = new ConfigPrincipal(); 6 ?> 7 <html> <head> 8 <title><?php echo $o_config->getParam('sistema_nome'); 9 ?></title> 10 ...

</head> 11 <body> 12 ... 13 </body> 14</html> 15 16

Agora que seja necessrio usar essa mesma classe em outra parte ou camada do cdigo, como abaixo. 1 <?php require_once 'ConfigPrincipal.php'; 2 3 /** 4 * Controlador ou Controller padro do sistema 5 */ 6 class IndexController { 7 /** 8 * Ao ou Action padro do sistema 9 */ public function IndexAction() 10 { 11 /** 12 * Criando um array com dados 13 * ficticios de clientes * @var Array 14 */ 15 $v_email_clientes = array 16 ( 17 'Joao' => 'joao@domain.com.br', 18 'Carlos' => 'carlos@domain.com.br', 'Pedro' => 'pedro@domain.com.br', 19 'Marcos' => 'marcos@marcos.com.br' 20 ); 21 22 23 /* 24 * instanciando a classe de configurao para 25 * obter o e-mail do administrador */ 26 $o_config = new ConfigPrincipal(); 27 $st_adm_email = $o_config->getParam('adm_email'); 28 29 foreach( $v_email_clientes AS $st_cliente => 30$st_email_cliente ) $this->enviaEmail 31 ( 32 $st_adm_email, 33 $st_adm_email, 34 'E-mail Teste', 35 'Texto E-mail Teste' ); 36 } 37 38 /** 39 * Metodo de envio de e-mail 40 */

private function enviaEmail( $st_de , $st_para , $st_titulo , 41 $st_texto ) 42 { 43 /** 44 * @todo Implementar cdigo necessrio * para o funcionamento do mtodo 45 */ 46 } 47} 48?> 49 50 51 52 53 54 55 56

Perceberam que foram criadas duas instncias da classe ConfigPrincipal? E se fosse necessrio inserir mais parmetros na classe de configurao e usar os tais em outros mtodos, camadas e arquivos do software? Seria necessrio instanciar a classe algumas outras vezes e as instncias teriam uso curto e pontual, alm disso mais memria seria alocada para cada uma delas. E sobre o fato de inserir novos parmetros na classe, em vrios lugares do cdigo, e uslos em outros lugares? E para o caso de ser necessrio existir apenas uma instncia da classe para todo o cdigo. Como voc faria? Antes de responderem, vejam o que eu encontro com muita frequncia por ai. Editei o arquivo index.php para demonstrar. 1 <?php //incluindo o arquivo de configurao principal 2 require_once 'ConfigPrincipal.php'; 3 4 /* 5 * Adicionando parametros 6 */ 7 8 $o_config = new ConfigPrincipal(); 9 //Adiconando e-mail para envio de e-mail que no devem ser 10respondidos 11$o_config->addParam('email_noreply','noreply@domain.com.br'); 12 13//Adiconando outros parametros aleatorios 14$o_config->addParam('xx','xxxx'); 15$o_config->addParam('yy','xxyy'); $o_config->addParam('zz','zzzz'); 16 17?> 18<html> <head> 19 <title><?php echo $o_config->getParam('sistema_nome'); 20 ?></title> 21 ... 22 </head>

<body> 23 ... 24 </body> 25</html> 26 27 28

Agora observem o cdigo abaixo, onde fiz a chamada de uma varivel global no meio de um mtodo. 1 <?php require_once 'ConfigPrincipal.php'; 2 3 /** 4 * Controlador ou Controller padro do sistema 5 */ 6 class IndexController { 7 /** 8 * Ao ou Action padro do sistema 9 */ public function IndexAction() 10 { 11 /** 12 * Criando um array com dados 13 * fictcios de clientes * @var Array 14 */ 15 $v_email_clientes = array 16 ( 17 'Joao' => 'joao@domain.com.br', 18 'Carlos' => 'carlos@domain.com.br', 'Pedro' => 'pedro@domain.com.br', 19 'Marcos' => 'marcos@marcos.com.br' 20 ); 21 22 23 /* 24 * instanciando a classe de configurao para 25 * obter o e-mail do administrador */ 26 global $o_config; 27 $st_noreply_email = $o_config->getParam('email_noreply'); 28 29 foreach( $v_email_clientes AS $st_cliente => 30$st_email_cliente ) $this->enviaEmail 31 ( 32 $st_noreply_email , 33 $st_adm_email, 34 'E-mail Teste', 35 'Texto E-mail Teste' ); 36 } 37 38 /** 39 * Metodo de envio de e-mail 40 */

private function enviaEmail( $st_de , $st_para , $st_titulo , 41 $st_texto ) 42 { 43 /** 44 * @todo Implementar cdigo necessrio * para o funcionamento do mtodo 45 */ 46 } 47} 48?> 49 50 51 52 53 54 55 56

Se vocs j viram isso por ai ou j implementaram algo parecido, tenham conscincia que o uso de variveis globais ultrapassado, em alguns casos causam falhas de segurana e contradiz totalmente o fator agregao, composio, herana e encapsulamento do paradigma de orientao a objeto. Mas ento, como resolver tantos problemas mostrados acima?

O Padro Singleton PHP


Como falei acima, a ideia do padro de projeto Singleton no permitir que em exista mais de uma instncia de uma determinada classe para todo o cdigo. As vantagens principais disso so mnimo de alocao de memria, sada para o problema de criao de variveis globais, um dado encapsulado em uma rea de cdigo persiste e pode ser acessado em vrios outros lugares at que a execuo do software chegue ao fim. Vamos ao segredo da implementao do Singleton PHP. Para demonstrar o mesmo, reescrevi as classes e cdigos j usadas acima, comeando pela ConfigPrincipal. 1 /** 2 * Classe de configurao principal do sistema * @author DigitalDev 3 */ 4 require_once 'Config.php'; 5 class ConfigPrincipal extends Config 6 { /* 7 * Varivel que ser usada para 8 * guardar a nica instncia da classe 9 * ConfigPrincipal */ 10 static private $o_instance; 11 12 /** 13 * O construtor passou de public para private 14 */ 15 private function __construct()

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 } 41 42 43 44 45 46 47 48

{ parent::__contruct(); //definindo algumas configuraes $this->setParam('sistema_nome', 'DigitalDev Site'); $this->setParam('adm_nome','Tarcisio Ruas'); $this->setParam('adm_email','contato@digitaldev.com.br'); } /** * Mtodo responsvel pela mgica da * nica instncia da classe ConfigPrincipal * @return ConfigPrincipal */ static function getInstance() { /** * A classe j foi instanciada? Se no, instancie... */ if(!isset(self::$o_instance)) { $st_class = __CLASS__; self::$o_instance = new $st_class(); } //retorne a instncia return self::$o_instance; }

A primeira mudana foi a troca no modo em que o mtodo __construct da classe ConfigPrincipal acessado, passando o mesmo de public para static. Isso evita que instncias da classe sejam criadas usando a instruo new como no cdigo mostrado abaixo. A tentativa de usar tal instruo resultar em um erro. 1<?php 2 3require_once 'ConfigPrincipal.php'; 4 5//isso no executar, retornando um erro no PHP 6$o_config = new ConfigPrincipal(); 7 8?> Agora, para conseguir acessar a instncia nica da classe ConfigPrincipal, necessrio usar seu mtodo ConfigPrincipal::getInstance(), como mostrado no cdigo abaixo.

1<?php 2 3require_once 'ConfigPrincipal.php'; 4 5//isso ir funcionar, retornado a instncia nica da classe 6$o_config = ConfigPrincipal::getInstance(); 7 8?> Vejam a como usar a classe ConfigPrincipal, agora implementada usando o padro Singleton PHP nos outros arquivos e camadas do software. 1 2 <?php o arquivo de configurao principal 3 //incluindo require_once 'ConfigPrincipal.php'; 4 5 //recuperando a instncia nica da classe 6 $o_config = ConfigPrincipal::getInstance(); 7 ?> 8 <html> <head> 9 <title><?php echo $o_config->getParam('sistema_nome'); 10?></title> ... 11 </head> 12 <body> 13 ... 14 </body> 15</html> 16 e na classe IndexControler 1 <?php 2 require_once 'ConfigPrincipal.php'; 3 /** 4 * Controlador ou Controller padro do sistema 5 */ 6 class IndexController 7 { /** 8 * Ao ou Action padro do sistema 9 */ 10 public function IndexAction() { 11 /** 12 * Criando um array com dados 13 * ficticios de clientes 14 * @var Array */ 15 $v_email_clientes = array 16 ( 17 'Joao' => 'joao@domain.com.br', 18 'Carlos' => 'carlos@domain.com.br', 19 'Pedro' => 'pedro@domain.com.br',

'Marcos' => 'marcos@marcos.com.br' 20 ); 21 22 23 24 //usando a instncia nica da classe ConfigPrincipal 25 $o_config = ConfigPrincipal::getInstance(); 26 $st_noreply_email = $o_config->getParam('email_noreply'); 27 28 foreach( $v_email_clientes AS $st_cliente => 29$st_email_cliente ) $this->enviaEmail 30 ( 31 $st_noreply_email , 32 $st_adm_email, 'E-mail Teste', 33 'Texto E-mail Teste' 34 ); 35 } 36 37 /** 38 * Metodo de envio de e-mail */ 39 private function enviaEmail( $st_de , $st_para , $st_titulo , 40 $st_texto ) 41 { 42 /** 43 * @todo Implementar cdigo necessrio * para o funcionamento do mtodo 44 */ 45 } 46} 47?> 48 49 50 51 52 53 54

E assim se d a implementao do padro de projeto Singleton, que aqui nesse post chamei vrias vezes de Singleton PHP, pelo fato de ter usando a linguagem PHP para escrever o cdigo. Dei um exemplo simples de como e onde usar o padro com uma classe de configurao, mas se observarmos nossos programas com ateno, encontraremos vrias outras aplicaes para o Singleton PHP. Se houver qualquer dvida sobre esse post, sobre o blog ou sugesto, usem a rea de perguntas e respostas abaixo. Obrigado. Alguns links sobre o assunto: Patterns php.net Singleton Wikipedia

Você também pode gostar