PHP’de Singleton Tasarım Deseni’ni neden kullanmalıyız?

Kaynak tüketen bir sınıftan oluşturulabilecek örnek sayısını yalnızca bir ile sınırlamak için singleton modelini kullanıyoruz. Kaynak tüketen sınıflar, web sitemizi yavaşlatabilecek veya maliyetli olabilecek sınıflardır. Örneğin:

  • Bazı harici hizmet sağlayıcılar (API’ler) her kullanım için ücret alır.
  • Mobil cihazları algılayan bazı sınıflar web sitemizi yavaşlatabilir.
  • Bir veritabanıyla bağlantı kurmak zaman alıyor ve uygulamamızı yavaşlatıyor.

Bu nedenle, tüm bu durumlarda, pahalı sınıftan oluşturduğumuz nesne sayısını yalnızca bir tane ile sınırlamak iyi bir fikirdir.

Singleton modelin anatomisi

Singleton modeline uyan bir sınıfın yapısal özelliklerini anlayarak başlayalım:

  1. Sınıftan doğrudan nesne oluşturulmasını önlemek için özel bir kurucu kullanılır.
  2. Pahalı işlem, özel kurucu içinde gerçekleştirilir.
  3. Sınıftan bir örnek oluşturmanın tek yolu, nesneyi yalnızca önceden yaratılmamışsa oluşturan statik bir yöntem kullanmaktır.

[php]
class Singleton {
// Hold the class instance.
private static $instance = null;

// The constructor is private
// to prevent initiation with outer code.
private function __construct() {
// The expensive process (e.g.,db connection) goes here.
}

// The object is created from within the class itself
// only if the class has no instance.
public static function getInstance() {
if (self::$instance == null) {
self::$instance = new Singleton();
}

return self::$instance;
}
}
[/php]

Neden tek kişilik?

Bir sınıftan yaratılabilecek nesne sayısını yalnızca bir tane ile sınırladığımız için, tüm değişkenler aynı, tek nesneyi işaret ediyor.

[php]
// All the variables point to the same object.
$object1 = Singleton::getInstance();
$object2 = Singleton::getInstance();
$object3 = Singleton::getInstance();
[/php]

Pratik örnek::veritabanı sınıfı

Veritabanı bağlantısı kuran ve örnek sayısını yalnızca bir ile sınırlayan bir sınıfla singleton modelini gösterelim.

[php]
// Singleton to connect db.
class ConnectDb {
// Hold the class instance.
private static $instance = null;
private $conn;

private $host = ‘localhost’;
private $user = ‘db user-name’;
private $pass = ‘db password’;
private $name = ‘db name’;

// The db connection is established in the private constructor.
private function __construct() {
$this->conn = new PDO("mysql:host={$this->host};
dbname={$this->name}", $this->user,$this->pass,
array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES ‘utf8’"));
}

public static function getInstance() {
if (!self::$instance) {
self::$instance = new ConnectDb();
}

return self::$instance;
}

public function getConnection() {
return $this->conn;
}
}
[/php]

Yeni bir bağlantı kurmadan önce bir bağlantının var olup olmadığını kontrol eden bir sınıf kullandığımız için, sınıftan kaç kez yeni bir nesne oluşturduğumuzun bir önemi yoktur, yine de aynı bağlantıyı elde ederiz. Bu noktayı kanıtlamak için, sınıftan üç örnek oluşturalım ve var dökümü yapalım.

[php]
$instance = ConnectDb::getInstance();
$conn = $instance->getConnection();
var_dump($conn);

$instance = ConnectDb::getInstance();
$conn = $instance->getConnection();
var_dump($conn);

$instance = ConnectDb::getInstance();
$conn = $instance->getConnection();
var_dump($conn);
[/php]

Sonuç, üç örnek için aynı bağlantıdır.

Veritabanıyla iletişim kurmak için tekil kullanmayan sınıf

Singleton deseninin çözdüğü sorunu anlamak için, yeni bir bağlantı kurmadan önce bir bağlantının var olup olmadığını kontrol edecek bir mekanizması olmayan aşağıdaki sınıfı ele alalım.

[php]
// Connect db without a singleton.
class ConnectDbWOSingleton {
private $conn;

private $host = ‘localhost’;
private $user = ‘db user-name’;
private $pass = ‘db password’;
private $name = ‘db name’;

// Public constructor.
public function __construct() {
$this->conn = new PDO("mysql:host={$this->host};
dbname={$this->name}", $this->user,$this->pass,
array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES ‘utf8’"));
}

public function getConnection() {
return $this->conn;
}
}
[/php]

Artık her yeni nesne oluşturduğumuzda yeni bir veritabanı bağlantısı da kuruyoruz.

[php]
$instance = new ConnectDbWOSingleton();
$conn = $instance->getConnection();
var_dump($conn);

$instance = new ConnectDbWOSingleton();
$conn = $instance->getConnection();
var_dump($conn);

$instance = new ConnectDbWOSingleton();
$conn = $instance->getConnection();
var_dump($conn);
[/php]

Bunun, veritabanıyla yapılan her yeni bağlantının zamana mal olması nedeniyle sistemi yavaşlatma etkileri vardır.

Sonucu kendiniz görmek için kodu çalıştırmanızı tavsiye ederim.