Back-End

1 ago, 2018

O padrão Singleton com PHP

Publicidade

Introdução

Esse artigo é para ser o primeiro de uma série de artigos que vou escrever para documentar os meus estudos sobre o Design Pattern (Padrões de Projeto) e aproveitar para compartilhar esses estudos com a comunidade em forma de artigos.

Nesta série, vou demonstrar alguns dos principais padrões de projeto do mercado. A minha ideia não é falar de todos os padrões existentes, mas sim explicar alguns dos principais e demonstrar com um exemplo a sua implementação na linguagem PHP.

Design Patterns

Antes de partirmos para o nosso primeiro padrão, como esse é o primeiro artigo dessa série, achei melhor dar um pequena explicação sobre o que são os padrões de projeto de uma forma mais ampla e contar um pouco da sua história.

Para começar, nada melhor do que citar um dos livros de maior referência sobre o assunto; estou falando do “Padrões de Projeto – Soluções Reutilizáveis de Software Orientado a Objetos”, da famosa Gang of Four (Gangue dos Quatro) de 1994, onde os quatro autores “Erich Gamma”, “John Vlissides”, “Ralph Johnson” e “Richard Helm” descrevem 24 design patterns. Eles os separam em três categorias: padrões de criação, padrões estruturais e padrões comportamentais. Nesta série eu vou escolher dois padrões de cada categoria para explicar e demonstrar o seu funcionamento.

Apesar de existirem mais do que os 24 padrões mencionados, este livro, mesmo nos dias atuais – como mencionado anteriormente – é uma das maiores referências sobre o assunto.

Singleton Pattern

Agora podemos começar, e para isso, achei melhor falar sobre o padrão de criação Singleton. Vou explicar a sua estrutura, qual problema ele busca resolver, e mostrar um exemplo de como podemos usar esse padrão nos nossos projetos desenvolvidos com PHP.

Problema a resolver

O padrão Singleton prega a ideia da instância única, onde quando você tenta criar uma instância da sua classe, essa classe deve verificar a existência da instância para que se a instância não existir, criar uma nova, e caso contrário retornar a mesma instância sem criar uma nova, garantindo assim menor consumo de memória e um único ponto de acesso global para esse recurso.

O Singleton tem uma estrutura bem simples e de fácil compreensão, como na imagem abaixo.

Esse é o diagrama UML do padrão Singleton

Esse padrão é bastante usado para o desenvolvimento de classes responsáveis pelo gerenciamento da conexão com o banco de dados ou o gerenciamentos de logs, nos permitindo ter acesso a esses recursos na nossa aplicação de forma rápida e descomplicada.

Implementação normal

Agora finalmente falaremos de código, mas primeiro vamos criar uma classe da forma convencional – uma pequena classe de Logs. Vou usar esse exemplo para demostrar que a cada instância criada estamos literalmente criando uma nova instância na memória.

<?php
class Log
{
}

$log = new Log;
$log2 = new Log;
$log3 = new Log;
$log4 = new Log;
$log5 = new Log;

var_dump($log);
var_dump($log2);
var_dump($log3);
var_dump($log4);
var_dump($log5);

Se executarmos o exemplo acima, poderemos ver que a cada nova chamada da classe Log, nós criamos uma nova instância, começando com #1 e indo até #5.

object(Log)#1 (0) {
}
object(Log)#2 (0) {
}
object(Log)#3 (0) {
}
object(Log)#4 (0) {
}
object(Log)#5 (0) {
}

Implementação Singleton

Agora vamos começar a implementar o padrão Singleton na nossa classe. Faremos isso alterando a visibilidade dos nosso métodos mágicos *__construct* o *__wakeup* e do *__clone*.

private function __construct()
{
}

private function __clone()
{
}

private function __wakeup()
{
}

Com isso, garantimos que a classe não pode ser mais instanciada de forma normal.

Vamos criar uma propriedade privada estática $instance

private static $instance;

E também vamos criar um método estático getInstance que vai ser o único responsável por retornar a nova instância da nossa classe. É neste método que vamos verificar se já existe uma instância na nossa classe.

public static function getInstance()
{
    if(self::$instance === null){
        self::$instance = new self;
    }
    return self::$instance;
}

Se der certo, vamos ter um arquivo como no exemplo abaixo.

<?php
class Log
{
    private static $instance;

    private function __construct()
    {
    }

    private function __clone()
    {
    }

    private function __wakeup()
    {
    }

    public static function getInstance()
    {
        if(self::$instance === null){
            self::$instance = new self;
        }
        return self::$instance;
    }
}

Agora com a nossa classe devidamente modificada, podemos testar o nosso exemplo.

$log = Log::getInstance();
$log2 = Log::getInstance();
$log3 = Log::getInstance();
$log4 = Log::getInstance();
$log5 = Log::getInstance();

var_dump($log);
var_dump($log2);
var_dump($log3);
var_dump($log4);
var_dump($log5);

No exemplo acima, agora com o nosso Singleton funcionando, vamos ver que a nossa instância é sempre a mesma #1. Conseguimos garantir a mesma instância, não importa quantas vezes chamamos a nossa classe.

object(Log)#1 (0) {
}
object(Log)#1 (0) {
}
object(Log)#1 (0) {
}
object(Log)#1 (0) {
}
object(Log)#1 (0) {
}

Singleton é um anti pattern?

Para muitos desenvolvedores o, Singleton é considerado um anti patterns, mas por que será? Acredito que uns dos principais motivos é pela natureza estática. Isso nos traz alguns problemas como não podermos trabalhar com interfaces e o aumento de acoplamento na classe. Além disso, como estamos falando de acesso global, existe um perigo de sobrescrever o comportamento da classe e gerar comportamentos inesperados no sistema.

Acredito que esses dois são os principais motivos para que o Singleton tenha esse estigma, mas na minha opinião ele é um padrão como qualquer outro; tem suas vantagens e desvantagens, e cabe ao desenvolvedor ter a sabedoria para saber quando e onde usá-lo.

Conclusão

Como falei anteriormente, esse artigo é o primeiro de uma série que pretendendo escrever para compartilhar os meus estudos com a comunidade. Comecei falando do Singleton por ser um padrão bastante famoso e de fácil compreensão. Espero que com esses pequenos passos tenham mostrado como podemos facilmente criar a nossa classe usando o Singleton no PHP.

Referências