Patrón Singleton
Parte de la sección Programación Orientada a Objetos del Journey de PHP de Coddy — lección 71 de 91.
El Patrón Singleton es un patrón de diseño creacional que garantiza que una clase tenga una única instancia a lo largo del ciclo de vida de su aplicación. También proporciona un punto de acceso global a esa instancia.
Este patrón es útil cuando necesitas exactamente un objeto para coordinar acciones en todo el sistema, como una conexión a la base de datos, un gestor de configuración o un registrador (logger). Crear múltiples instancias de estos desperdiciaría recursos o causaría un comportamiento inconsistente.
Aquí tienes cómo implementar un Singleton en PHP:
<?php
class Database {
private static ?Database $instance = null;
private function __construct() {
// El constructor privado evita la instanciación directa
}
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";
Resultado:
Same instanceEl patrón se basa en tres elementos clave: un constructor privado que impide el uso de new directamente, una propiedad estática que mantiene la instancia única y un método estático que crea la instancia en la primera llamada y la devuelve en las llamadas posteriores.
Para que el Singleton sea verdaderamente a prueba de balas, también debes evitar la clonación y la deserialización:
<?php
private function __clone() {}
public function __wakeup() {
throw new Exception("Cannot unserialize singleton");
}
Desafío
FácilVamos a construir un gestor de configuración utilizando el Patrón Singleton. En aplicaciones reales, normalmente se desea una única fuente de verdad para los ajustes de configuración; tener múltiples objetos de configuración podría provocar un comportamiento inconsistente en todo el sistema.
Organizarás tu código en dos archivos:
Config.php— Crea una claseConfigque implemente el Patrón Singleton. Tu gestor de configuración debe:- Almacenar los ajustes en una propiedad de array privada
- Tener un constructor privado que inicialice el array de ajustes como vacío
- Proporcionar un método estático
getInstance()que devuelva la instancia única - Evitar la clonación haciendo que
__clone()sea privado - Incluir un método
set(string $key, string $value): voidpara almacenar un ajuste - Incluir un método
get(string $key): ?stringque devuelva el valor de una clave, onullsi la clave no existe - Incluir un método
getAll(): arrayque devuelva todos los ajustes
main.php— Incluye el archivo Config. Recibirás dos entradas: una clave y un valor.Obtén la instancia de Config y establece un ajuste predeterminado con la clave
"app_name"y el valor"MyApp".Obtén una segunda referencia a la instancia de Config (usando
getInstance()de nuevo) y úsala para establecer otro ajuste utilizando la clave y el valor de las entradas.Finalmente, verifica que el Singleton esté funcionando correctamente:
- Imprime
"Same instance: true"o"Same instance: false"basándote en si ambas referencias apuntan al mismo objeto (usa===para comparar) - Imprime
"Settings count: [count]"mostrando el número total de ajustes almacenados (usacount()en el resultado degetAll()) - Imprime
"App name: [value]"mostrando el ajuste app_name recuperado a través de la segunda referencia
- Imprime
Este desafío demuestra el beneficio principal del Patrón Singleton: no importa cuántas veces llames a getInstance(), siempre obtendrás el mismo objeto, asegurando que todas las partes de tu aplicación compartan el mismo estado de configuración.
Pruébalo tú mismo
<?php
require_once 'Config.php';
// Leer entrada
$key = trim(fgets(STDIN));
$value = trim(fgets(STDIN));
// TODO: Obtener la instancia de Config y establecer "app_name" a "MyApp"
// TODO: Obtener una segunda referencia a Config usando getInstance() de nuevo
// TODO: Usar la segunda referencia para establecer el ajuste usando $key y $value de la entrada
// TODO: Verificar que el Singleton está funcionando:
// - Imprimir "Same instance: true" o "Same instance: false" basado en la comparación ===
// - Imprimir "Settings count: [count]" mostrando el total de ajustes
// - Imprimir "App name: [value]" mostrando app_name recuperado a través de la segunda referencia
?>Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de OOP
Archivos externosIntroducción a OOPClases vs ObjetosLa palabra clave $thisMétodosPropiedadesConstructor (__construct)Destructor (__destruct)Resumen - Calculadora simple4Herencia
Herencia básicaLa palabra clave parent::Sobrescritura de métodosLa palabra clave finalClases abstractasResumen - Jerarquía de empleados7Encapsulamiento
Público, Protegido, PrivadoModificadores de acceso a fondoGetters y SettersOcultamiento de informaciónPromoción de constructor (8.0)Resumen - Sistema de registros de estudiantes10Conceptos avanzados de POO
Composición vs. HerenciaInyección de dependenciasClases anónimasEnums (PHP 8.1)Fibers (PHP 8.1)Clonación de objetos a fondoGeneradores e Iteradores13Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón Repository2Espacios de nombres y Autoloading
Introducción a los espacios de nombresLa palabra clave useEstándar de Autoloading PSR-4Autoloader de ComposerResumen - Proyecto organizado5Interfaces y Contratos
Introducción a las InterfacesImplementación de InterfacesImplementación de Múltiples InterfacesInterfaz vs Clase AbstractaType Hinting con InterfacesResumen - Calculadora de Formas8Métodos mágicos
Introducción a los métodos mágicos__toString y __debugInfo__get, __set, __isset, __unset__call y __callStatic__clone y clonación de objetos__serialize y __unserializeResumen - Colección personalizada3Propiedades de clase
Propiedades de instancia vs. estáticasConstantes en clasesMétodos y propiedades estáticosPropiedades privadas y protegidasPropiedades de solo lectura (PHP 8.1)Resumen - Gestor de cuenta bancaria6Polimorfismo
Sobrescritura de métodos revisadaPolimorfismo mediante interfacesType Hinting y tipos de uniónEnlace estático tardíoResumen - Procesador de pagos9Traits
Introducción a los TraitsUso de múltiples TraitsResolución de conflictos de TraitsMétodos abstractos en TraitsTraits frente a herencia12Patrones de diseño Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón Strategy