Menu
Coddy logo textTech

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 instance

El 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");
}
challenge icon

Desafío

Fácil

Vamos 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 clase Config que 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): void para almacenar un ajuste
    • Incluir un método get(string $key): ?string que devuelva el valor de una clave, o null si la clave no existe
    • Incluir un método getAll(): array que 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 (usa count() en el resultado de getAll())
    • Imprime "App name: [value]" mostrando el ajuste app_name recuperado a través de la segunda referencia

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.

Hoja de referencia

El Patrón Singleton asegura que una clase tenga una única instancia a lo largo del ciclo de vida de su aplicación y proporciona un punto de acceso global a dicha instancia.

Este patrón es útil para objetos como conexiones a bases de datos, gestores de configuración o loggers, donde múltiples instancias desperdiciarían recursos o causarían un comportamiento inconsistente.

Implementación básica de Singleton:

<?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;
    }
}

$db1 = Database::getInstance();
$db2 = Database::getInstance();

echo $db1 === $db2 ? "Same instance" : "Different instances";
// Salida: Same instance

Elementos clave:

  • Constructor privado — evita el uso de new directamente
  • Propiedad estática — contiene la instancia única
  • Método estático — crea la instancia en la primera llamada y la devuelve en las llamadas posteriores

Previniendo la clonación y la deserialización:

<?php
private function __clone() {}

public function __wakeup() {
    throw new Exception("Cannot unserialize singleton");
}

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

?>
quiz iconPonte a prueba

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