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
ParentClassHer 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
ChildClassstatic:: 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.
Görev
KolayGeç 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 birModelsınıfı oluşturun. Onu çağıran sınıfın yeni bir örneğini döndürmek içinnew static()kullanan statik bircreate()yöntemi ekleyin.static::$tableNamedöndüren başka bir statikgetTable()yöntemi ekleyin. Son olarak,static::classvestatic::$tableNamekullanarak"[ClassName] from table [tableName]"döndüren birdescribe()yöntemi ekleyin.User.php—Modelsınıfını genişleten birUsersınıfı oluşturun. Üst dosyayı dahil edin. Statik$tableNameözelliğini"users"olarak geçersiz kılın (override). Sınıf,Modelsınıfındaki tüm yöntemleri herhangi bir değişiklik yapmadan miras alır.Product.php—Modelsınıfını genişleten birProductsı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. HemUserhem deProductörnekleri oluşturmak için miras alınancreate()fabrika yöntemini kullanın. Her örnek içindescribe()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()veProduct::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
?>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
1OOP Temelleri
Harici DosyalarOOP'ye GirişSınıflar ve Nesneler$this Anahtar KelimesiMetotlarÖzelliklerYapıcı Metot (__construct)Yıkıcı Metot (__destruct)Özet - Basit Hesap Makinesi4Kalıtım
Temel Kalıtımparent:: Anahtar KelimesiMetot Geçersiz Kılmafinal Anahtar KelimesiSoyut SınıflarÖzet - Çalışan Hiyerarşisi7Kapsülleme
Public, Protected, PrivateErişim Belirleyicilere Derinlemesine BakışGetter ve Setter MetotlarıBilgi GizlemeConstructor Promotion (8.0)Özet - Öğrenci Kayıt Sistemi10İleri Düzey OOP Kavramları
Kompozisyon vs KalıtımDependency InjectionAnonim SınıflarEnum'lar (PHP 8.1)Fiber'lar (PHP 8.1)Nesne Klonlama: Derinlemesine İncelemeGenerator'lar ve Iterator'lar13Tasarım Kalıpları Bölüm 2
Komut KalıbıAdaptör KalıbıDekoratör KalıbıŞablon Metot KalıbıDurum KalıbıKompozit KalıbıRepository Kalıbı2İsim Alanları ve Autoloading
İsim Alanlarına Girişuse Anahtar KelimesiPSR-4 Autoloading StandartıComposer AutoloaderÖzet - Düzenli Proje5Arayüzler ve Sözleşmeler
Arayüzlere GirişArayüzleri UygulamaBirden Fazla Arayüz UygulamaArayüz vs Soyut SınıfArayüzler ile Tip BelirlemeÖzet - Şekil Hesaplayıcı8Sihirli Metotlar
Sihirli Metotlara Giriş__toString & __debugInfo__get, __set, __isset, __unset__call & __callStatic__clone & Nesne Klonlama__serialize & __unserializeÖzet - Özel Koleksiyon3Sınıf Özellikleri
Örnek ve Statik ÖzelliklerSınıflarda SabitlerStatik Metotlar ve ÖzelliklerPrivate ve Protected ÖzelliklerReadonly Özellikler (PHP 8.1)Özet - Banka Hesabı Yöneticisi6Çok Biçimlilik
Metot Geçersiz Kılmaya Yeniden BakışArayüzler ile Çok BiçimlilikType Hinting ve Union TypesLate Static BindingÖzet - Ödeme İşlemcisi9Trait'ler
Trait'lere GirişÇoklu Trait KullanımıTrait Çakışma ÇözümüTrait'lerde Soyut MetotlarTrait'ler ve Kalıtım12Tasarım Kalıpları Bölüm 1
Tasarım Kalıplarına GirişSingleton KalıbıFactory KalıbıObserver KalıbıStrategy Kalıbı15Final Meydan Okumaları
E-Öğrenme PlatformuBankacılık SistemiOyun Karakteri GeliştirmeAraç Kiralama Servisi