Wzorzec Singleton w PHP - Praktyczne zastosowanie

26.09.2025

Wzorzec projektowy Singleton w PHP 8.4

Standard Singleton to wzorzec kreacyjny zapewniający istnienie tylko jednej instancji klasy. Wykorzystuje nowości PHP 8.4 takie jak property hooks do eleganckiego zarządzania stanem aplikacji.

Dlaczego wzorzec Singleton jest ważny?

  • Gwarantuje istnienie tylko jednej instancji w całej aplikacji,
  • Zapewnia globalny punkt dostępu do współdzielonego zasobu,
  • Oszczędza pamięć przez eliminację wielokrotnego tworzenia tego samego obiektu,
  • Idealny dla kontenerów DI, loggerów i menedżerów konfiguracji.

Kluczowe cechy wzorca Singleton

  • Prywatny konstruktor - uniemożliwia tworzenie instancji z zewnątrz,
  • Statyczna metoda getInstance() - jedyny sposób uzyskania instancji,
  • Lazy loading - obiekt tworzony tylko gdy jest potrzebny,
  • Ochrona przed klonowaniem - blokada __clone() i serializacji.

Jak działa wzorzec Singleton?

Wzorzec Singleton to podejście projektowe, które zapewnia istnienie tylko jednej instancji klasy w całym cyklu życia aplikacji, przy jednoczesnym dostarczeniu globalnego punktu dostępu do tej instancji. Klasa Application z rozdziału 3 ebooka, która implementuje kontener zależności (Dependency Injection), stanowi świetny przykład wykorzystania tego wzorca. Metoda statyczna getInstance() zapewnia dostęp do pojedynczej instancji aplikacji, co gwarantuje, że każdy komponent korzysta z tej samej konfiguracji i zasobów. Na tym kursie, programiści PHP zdobywają umiejętności w zakresie obiektowego programowania oraz aplikacji

W kolejnych rozdziałach ebooka (np. rozdział 5), klasa Application została rozbudowana o kolejne istotne elementy, jak np. obsługa konfiguracji za pomocą właściwości config. Zastosowanie nowości z PHP 8.4, takich jak właściwości typu getter, operator przypisania null coalescing (??=) oraz jawne deklarowanie typów w bardziej zaawansowanych konstrukcjach, znacząco zwiększyło czytelność i ergonomię kodu. Właściwość config demonstruje, jak dzięki nowoczesnym funkcjom języka, singleton może być elegancko połączony z wzorcem leniwej inicjalizacji (lazy loading), zapewniając maksymalną wydajność aplikacji.

Dodatkowo w klasie Application zastosowano zabezpieczenia, które są integralną częścią prawidłowego użycia wzorca Singleton, takie jak blokada klonowania (__clone) oraz serializacji (__serialize, __unserialize). Dzięki temu mamy pewność, że instancja klasy pozostanie unikalna przez cały cykl życia aplikacji. Połączenie singletona z kontenerem zależności w przykładzie klasy Application to efektywne podejście, które znakomicie ilustruje, jak w praktyce można implementować zaawansowane wzorce projektowe, wykorzystując najnowsze możliwości PHP 8.4.

<?php

declare(strict_types=1);

namespace DJWeb\Framework\Base;

use DJWeb\Framework\Config\ConfigBase;
use DJWeb\Framework\Config\Contracts\ConfigContract;
use DJWeb\Framework\Container\Container;
use DJWeb\Framework\Container\Contracts\ContainerContract;
use DJWeb\Framework\Container\Contracts\ServiceProviderContract;
use DJWeb\Framework\DBAL\Contracts\Schema\SchemaContract;
use DJWeb\Framework\Events\EventManager;
use DJWeb\Framework\Exceptions\Container\ContainerError;
use DJWeb\Framework\Log\LoggerFactory;
use DJWeb\Framework\ServiceProviders\SchemaServiceProvider;
use Psr\Log\LoggerInterface;

class Application extends Container
{
    public string $base_path{
        get => $this->getBinding('base_path') ?? '';
    }

    public ?ConfigContract $config{
        get {
            $this->config ??= $this->get(ConfigContract::class);
            $this->config->loadConfig();
            return $this->config;
        }
    }

    protected static ?self $instance = null;
    protected function __construct()
    {
        parent::__construct();
        $this->set(Container::class, $this);
        $this->set(ContainerContract::class, $this);
        $this->set(ConfigContract::class, new ConfigBase($this));
    }

    public function __clone()
    {
        throw new ContainerError('Cannot clone Application');
    }

    public function __serialize(): array
    {
        return [];
    }

    /**
     * @param array<string, mixed> $data
     *
     * @return void
     */
    public function __unserialize(array $data): void
    {
        json_encode($data, JSON_THROW_ON_ERROR);
        throw new ContainerError('Cannot unserialize Application');
    }

    public static function getInstance(): static
    {
        if (self::$instance === null) {
            /** @phpstan-ignore-next-line instance */
            self::$instance = new static();
        }
        /** @phpstan-ignore-next-line instance */
        return self::$instance;
    }

    public static function withInstance(?self $instance): void
    {
        self::$instance = $instance;
    }
}

🎓 Chcesz poznać więcej wzorców projektowych?

Ten wpis to fragment kompleksowego kursu PHP 8.4, w którym szczegółowo omawiam wszystkie wzorce projektowe wraz z praktycznymi przykładami z rzeczywistych projektów.

Kup pełny kurs PHP 8.4 🚀 Pobierz darmowy fragment 📥

Zobacz też inne wzorce projektowe