Menu
Coddy logo textTech

Late Static Binding

Coddy'nin PHP Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 36 / 91.

Bir üst sınıfta self:: kullandığınızda, bu her zaman gerçekte kullanılan sınıfa değil, yazıldığı sınıfa atıfta bulunur. Bu durum, kalıtımda beklenmedik davranışlara neden olabilir. Geç statik bağlama (Late static binding), static:: anahtar kelimesini kullanarak bu sorunu çözer.

self:: ifadesinin beklendiği gibi çalışmadığı şu örneği inceleyelim:

<?php
class ParentClass {
    public static function create() {
        return new self();
    }
    
    public static function getClassName() {
        return self::class;
    }
}

class ChildClass extends ParentClass {}

$obj = ChildClass::create();
echo get_class($obj) . "\n";
echo ChildClass::getClassName();

Çıktı:

ParentClass
ParentClass

Her ne kadar ChildClass::create() çağırmış olsak da, self:: derleme zamanında çözümlendiği için bir ParentClass nesnesi elde ettik. Şimdi bunun yerine static:: kullanalım:

<?php
class ParentClass {
    public static function create() {
        return new static();
    }
    
    public static function getClassName() {
        return static::class;
    }
}

class ChildClass extends ParentClass {}

$obj = ChildClass::create();
echo get_class($obj) . "\n";
echo ChildClass::getClassName();

Çıktı:

ChildClass
ChildClass

static:: ile PHP, hangi sınıfın kullanılacağını belirlemek için çalışma zamanına (runtime) kadar bekler. Karar geciktirildiği için buna "geç" (late) bağlama denir. Fabrika (factory) metotları ve kalıtıma uyması gereken tüm statik metotlar için bu gereklidir.

Önemli Nokta: Alt sınıfların statik davranışı düzgün bir şekilde devralmasını ve özelleştirmesini istediğinizde self:: yerine static:: kullanın.

challenge icon

Görev

Kolay

Geç statik bağlamanın (late static binding) gücünü gösteren bir model kayıt sistemi oluşturalım. Alt sınıfların miras alabileceği bir fabrika yöntemine sahip temel bir Model sınıfı oluşturacaksınız — ve static:: sayesinde, her alt sınıf ebeveyn yerine doğru bir şekilde kendisinin örneklerini oluşturacaktır.

Kodunuzu dört dosya halinde düzenleyeceksiniz:

  • Model.php"models" olarak ayarlanmış korumalı bir statik özellik olan $tableName'e sahip temel bir Model sınıfı oluşturun. Onu çağıran sınıfın yeni bir örneğini döndürmek için new static() kullanan statik bir create() yöntemi ekleyin. static::$tableName döndüren başka bir statik getTable() yöntemi ekleyin. Son olarak, static::class ve static::$tableName kullanarak "[ClassName] from table [tableName]" döndüren bir describe() yöntemi ekleyin.
  • User.phpModel sınıfını genişleten bir User sınıfı oluşturun. Üst dosyayı dahil edin. Statik $tableName özelliğini "users" olarak geçersiz kılın (override). Sınıf, Model sınıfındaki tüm yöntemleri herhangi bir değişiklik yapmadan miras alır.
  • Product.phpModel sınıfını genişleten bir Product sınıfı oluşturun. Üst dosyayı dahil edin. Statik $tableName özelliğini "products" olarak geçersiz kılın. Yine, sınıf tüm yöntemleri üst sınıftan miras alır.
  • main.php — Hem User hem de Product dosyalarını dahil edin. Hem User hem de Product örnekleri oluşturmak için miras alınan create() fabrika yöntemini kullanın. Her örnek için describe() yöntemini çağırın ve sonucu kendi satırında yazdırın. Ardından, her sınıf için tablo adını User::getTable() ve Product::getTable() kullanarak, her biri kendi satırında olacak şekilde yazdırın.

Buradaki sihir, create() ve getTable() yöntemlerinin yalnızca üst Model sınıfında tanımlanmış olmasına rağmen, static:: bağlamayı çalışma zamanına kadar geciktirdiği için alt sınıflarla doğru şekilde çalışmasıdır. User::create() çağırdığınızda, PHP bir Model örneği değil, bir User örneği oluşturur; çünkü static:: aslında çağrılan sınıfa atıfta bulunur.

Çıktınız dört satır göstermelidir: User örneği için açıklama, Product örneği için açıklama, User tablo adı ve Product tablo adı.

Kopya kağıdı

Bir üst sınıftaki self:: anahtar kelimesi her zaman yazıldığı sınıfa atıfta bulunur ve derleme zamanında çözümlenir. static:: ile geç statik bağlama (late static binding), referansı çalışma zamanında çözümleyerek alt sınıfların statik davranışı düzgün bir şekilde devralmasına ve özelleştirmesine olanak tanır.

self:: Kullanımı (derleme zamanı bağlama)

<?php
class ParentClass {
    public static function create() {
        return new self();  // Always creates ParentClass
    }
    
    public static function getClassName() {
        return self::class;  // Always returns "ParentClass"
    }
}

class ChildClass extends ParentClass {}

$obj = ChildClass::create();  // Returns ParentClass instance
echo ChildClass::getClassName();  // Outputs: ParentClass

static:: Kullanımı (çalışma zamanı bağlama)

<?php
class ParentClass {
    public static function create() {
        return new static();  // Creates instance of calling class
    }
    
    public static function getClassName() {
        return static::class;  // Returns calling class name
    }
}

class ChildClass extends ParentClass {}

$obj = ChildClass::create();  // Returns ChildClass instance
echo ChildClass::getClassName();  // Outputs: ChildClass

Önemli Nokta: Alt sınıfların statik davranışı düzgün bir şekilde devralmasını ve özelleştirmesini istediğinizde self:: yerine static:: kullanın. Bu, fabrika yöntemleri ve kalıtıma uyması gereken tüm statik yöntemler için gereklidir.

Kendin dene

<?php

require_once 'User.php';
require_once 'Product.php';

// TODO: Bir User örneği oluşturmak için kalıtım alınan create() fabrika yöntemini kullanın

// TODO: Bir Product örneği oluşturmak için kalıtım alınan create() fabrika yöntemini kullanın

// TODO: User örneği üzerinde describe() yöntemini çağırın ve sonucu yazdırın

// TODO: Product örneği üzerinde describe() yöntemini çağırın ve sonucu yazdırın

// TODO: User::getTable() değerini yazdırın

// TODO: Product::getTable() değerini yazdırın

?>
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Yönelimli Programlama bölümündeki tüm dersler