Design Pattern: Singleton
Tags: programming, productivity
Published: 2021-10-25 12:51:05

> Permite que você garanta que uma classe tenha apenas uma instância, enquanto provê acesso global para ela.

O padrão Singleton resolve esses dois problemas de uma vez, mas por outro lado viola o *princípio de responsabilidade única.*

## Explicando o problema

1. Permite que você garanta que uma classe tenha apenas uma instância.
    
    Você deve estar se perguntando o motivo de alguém querer isso, mas um bom exemplo é quando precisamos usar em vários pontos da aplicação um recurso compartilhado, como por exemplo a conexão com o banco de dados. Quando criado um objeto, ao precisar usar ele novamente a aplicação irá te devolver o mesmo objeto criado anteriormente ao invés de criá-lo novamente.
    
2. Provê acesso global para uma instância.
    
    > Quem nunca criou aquela variável global no index para ser usado ao longo do projeto? Nunca fez? É, eu já fiz hehe
    > 
    
    São bem úteis, não irei mentir pra você, mas são bem inseguras, pois o seu conteúdo pode ser alterado por qualquer código e criar um efeito colateral na sua aplicação.
    
    Na mesma ideia de uma variável global, o Singleton permite que você acesse uma instância de uma classe globalmente em qualquer lugar da aplicação, mas previne que o seu conteúdo seja sobrescrito por outro código.
    

## Como implementar

1. Crie um campo privado estático na classe para o guardar a instância.

```php
<?php
class Database 
{
    private static $instance;
// Continuação da classe...
```

1. Declare um método de criação público e estático para obter a instância singleton Ex: `getInstance`.

```php
// Inicio da classe...

public static function getInstance() 
{
    // Implementação da função 
}

// Continuação da classe...
```

1. Implemente a inicialização dentro do método estático. Ela deve criar um novo objeto na sua primeira chamada e colocá-lo no campo estático. O método deve sempre retornar aquela instância em todas as chamadas posteriores.

```php
// Inicio da classe...

public static function getInstance() 
{
    if (is_null(self::$instance)) {
        echo 'Passou aqui uma só vez' . PHP_EOL;
        self::$instance = new self();
    }
    
    return self::$instance;
}

// Continuação da classe...
```

OBS: Se tiver trabalhando com multi thread, dever colocar um thread lock antes do operador `new` no método `getInstance`.

1. Pode parecer estranho, mas faça o construtor da classe ser privado. O método estático da classe vai conseguir chamar o construtor, mas irá previnir a criação através de outros objetos.

```php
// Inicio da classe...

private function __construct() 
{
    $this->connection = 'conectado';
}

// Continuação da classe...
```

1. Vá para o código cliente e faça a chamada para o método estático do singleton.

```php
$database = Database::getInstance();
```

### Agora vamos ver todo o código da implementação.

```php
<?php
class Database 
{
    private static $instance;
    private $connection;

    private function __construct() 
    {
        $this->connection = 'conectado';
    }

    public function query($sql) 
    {
        return 'Resultado da query: ' . $sql . PHP_EOL;
    }

    public static function getInstance() 
    {
        if (is_null(self::$instance)) {
            echo 'Passou aqui uma só vez' . PHP_EOL;
            self::$instance = new self();
        }
        return self::$instance;
    }
}

class User 
{
    public function getUser()
    {
        $database = Database::getInstance();
        return $database->query('SELECT * FROM Users;');
    }
}

class Transactions 
{
    public function getTransaction()
    {
        $database = Database::getInstance();
        return $database->query('SELECT * FROM Transactions;');
    }
}

// Case 1
$user = new User;
echo $user->getUser();

// Case 1
$transaction = new Transactions;
echo $transaction->getTransaction();

$database = new Database; //fatal error
```

Nas classes que representam as models `User e Transactions` a instância está dentro da função, mas numa implementação

## Conclusão

Use o singleton quando você ver a necessidade de uma classe possuir apenas uma instância disponível e global em sua aplicação e tbm caso precise de um controle mais estrito sobre as variáveis globais.



É isso galera, chegamos no fim de mais um artigo inté o próximo!