Padrão Singleton
Parte da seção Programação Orientada a Objetos do Journey de PHP da Coddy — lição 71 de 91.
O Padrão Singleton é um padrão de projeto criacional que garante que uma classe tenha apenas uma instância durante todo o ciclo de vida da sua aplicação. Ele também fornece um ponto de acesso global a essa instância.
Este padrão é útil quando você precisa de exatamente um objeto para coordenar ações em todo o sistema, como uma conexão de banco de dados, gerenciador de configuração ou logger. Criar múltiplas instâncias destes desperdiçaria recursos ou causaria um comportamento inconsistente.
Veja como implementar um Singleton em PHP:
<?php
class Database {
private static ?Database $instance = null;
private function __construct() {
// O construtor privado impede a instanciação direta
}
public static function getInstance(): Database {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
public function query(string $sql): string {
return "Executing: $sql";
}
}
$db1 = Database::getInstance();
$db2 = Database::getInstance();
echo $db1 === $db2 ? "Same instance" : "Different instances";
Saída:
Same instanceO padrão baseia-se em três elementos-chave: um construtor privado que impede o uso de new diretamente, uma propriedade estática que mantém a instância única, e um método estático que cria a instância na primeira chamada e a retorna em chamadas subsequentes.
Para tornar o Singleton verdadeiramente à prova de balas, você também deve impedir a clonagem e a desserialização:
<?php
private function __clone() {}
public function __wakeup() {
throw new Exception("Cannot unserialize singleton");
}
Desafio
FácilVamos construir um gerenciador de configurações usando o Singleton Pattern. Em aplicações reais, você geralmente deseja uma única fonte de verdade para as definições de configuração — ter múltiplos objetos de configuração poderia levar a um comportamento inconsistente em todo o seu sistema.
Você organizará seu código em dois arquivos:
Config.php— Crie uma classeConfigque implemente o Singleton Pattern. Seu gerenciador de configurações deve:- Armazenar as configurações em uma propriedade de array privada
- Ter um construtor privado que inicializa o array de configurações como vazio
- Fornecer um método estático
getInstance()que retorna a instância única - Impedir a clonagem tornando o método
__clone()privado - Incluir um método
set(string $key, string $value): voidpara armazenar uma configuração - Incluir um método
get(string $key): ?stringque retorna o valor para uma chave, ounullse a chave não existir - Incluir um método
getAll(): arrayque retorna todas as configurações
main.php— Inclua o arquivo Config. Você receberá duas entradas: uma chave e um valor.Obtenha a instância de Config e defina uma configuração padrão com a chave
"app_name"e o valor"MyApp".Obtenha uma segunda referência para a instância de Config (usando
getInstance()novamente) e use-a para definir outra configuração usando a chave e o valor das entradas.Finalmente, verifique se o Singleton está funcionando corretamente:
- Imprima
"Same instance: true"ou"Same instance: false"com base no fato de ambas as referências apontarem para o mesmo objeto (use===para comparar) - Imprima
"Settings count: [count]"mostrando o número total de configurações armazenadas (usecount()no resultado degetAll()) - Imprima
"App name: [value]"mostrando a configuração app_name recuperada através da segunda referência
- Imprima
Este desafio demonstra o benefício central do Singleton Pattern: não importa quantas vezes você chame getInstance(), você sempre obtém o mesmo objeto, garantindo que todas as partes da sua aplicação compartilhem o mesmo estado de configuração.
Folha de consulta
O Padrão Singleton garante que uma classe tenha apenas uma instância durante todo o ciclo de vida da sua aplicação e fornece um ponto de acesso global a essa instância.
Este padrão é útil para objetos como conexões de banco de dados, gerenciadores de configuração ou loggers, onde múltiplas instâncias desperdiçariam recursos ou causariam comportamento inconsistente.
Implementação básica de Singleton:
<?php
class Database {
private static ?Database $instance = null;
private function __construct() {
// O construtor privado impede a instanciação direta
}
public static function getInstance(): Database {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
}
$db1 = Database::getInstance();
$db2 = Database::getInstance();
echo $db1 === $db2 ? "Same instance" : "Different instances";
// Saída: Same instance
Elementos-chave:
- Construtor privado — impede o uso direto de
new - Propriedade estática — contém a instância única
- Método estático — cria a instância na primeira chamada e a retorna nas chamadas subsequentes
Prevenindo clonagem e desserialização:
<?php
private function __clone() {}
public function __wakeup() {
throw new Exception("Cannot unserialize singleton");
}
Experimente você mesmo
<?php
require_once 'Config.php';
// Ler entrada
$key = trim(fgets(STDIN));
$value = trim(fgets(STDIN));
// TODO: Obter a instância de Config e definir "app_name" como "MyApp"
// TODO: Obter uma segunda referência para Config usando getInstance() novamente
// TODO: Usar a segunda referência para definir a configuração usando $key e $value da entrada
// TODO: Verificar se o Singleton está funcionando:
// - Imprimir "Same instance: true" ou "Same instance: false" com base na comparação ===
// - Imprimir "Settings count: [count]" mostrando o total de configurações
// - Imprimir "App name: [value]" mostrando app_name recuperado através da segunda referência
?>Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de POO
Arquivos ExternosIntrodução à POOClasses vs ObjetosA Palavra-chave $thisMétodosPropriedadesConstrutor (__construct)Destrutor (__destruct)Recapitulação - Calculadora Simples4Herança
Herança BásicaA Palavra-chave parent::Sobrescrita de MétodoA Palavra-chave finalClasses AbstratasRecapitulação - Hierarquia de Funcionários7Encapsulamento
Público, Protegido, PrivadoModificadores de Acesso em DetalhesGetters e SettersOcultação de InformaçãoPromoção de Construtor (8.0)Recapitulação - Sistema de Registro de Alunos10Conceitos Avançados de POO
Composição vs HerançaInjeção de DependênciaClasses AnônimasEnums (PHP 8.1)Fibers (PHP 8.1)Mergulho Profundo em Clonagem de ObjetosGeradores e Iteradores13Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositePadrão Repository2Namespaces e Autoloading
Introdução a NamespacesA Palavra-chave usePadrão de Autoloading PSR-4Autoloader do ComposerRecapitulação - Projeto Organizado5Interfaces e Contratos
Introdução a InterfacesImplementando InterfacesImplementação de Múltiplas InterfacesInterface vs Classe AbstrataType Hinting com InterfacesRecapitulação - Calculadora de Formas8Métodos Mágicos
Introdução aos Métodos Mágicos__toString e __debugInfo__get, __set, __isset, __unset__call e __callStatic__clone e Clonagem de Objetos__serialize e __unserializeRecapitulação - Coleção Personalizada11Sistema de Tipos e Tratamento de Erros
Declarações de TiposTipos AnuláveisTipos de União e InterseçãoClasses de ExceçãoHierarquia de Exceções PersonalizadasTry, Catch, FinallyRecapitulação - Validador de Formulário14Projeto: Gerenciamento de Biblioteca
Visão Geral do ProjetoClasses Livro e Usuário3Propriedades de Classe
Propriedades de Instância vs EstáticasConstantes em ClassesMétodos e Propriedades EstáticosPropriedades Privadas e ProtegidasPropriedades Readonly (PHP 8.1)Recapitulação - Gerenciador de Conta Bancária6Polimorfismo
Sobrescrita de Métodos RevisitadaPolimorfismo via InterfacesType Hinting e Union TypesLate Static BindingRecapitulação - Processador de Pagamentos9Traits
Introdução a TraitsUsando Múltiplos TraitsResolução de Conflitos de TraitsMétodos Abstratos em TraitsTraits vs Herança12Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão ObserverPadrão Strategy