Nitelikler

PHP 5.4.0 itibariyle, PHP tekrar tekrar kullanılabilen bir yöntem kodu olarak trait isminı kullanarak nitelikleri tanımlamıştır.

Nitelikler, PHP gibi tek kalıtımlı dillerde kodun yeniden kullanımını sağlayan bir mekanizmadır. Yöntem kümelerini farklı sınıf hiyerarşilerinde yaşayan birçok bağımsız sınıfın içinde özgürce yeniden kullanımını mümkün kılarak tek kalıtımlı dillerdeki bazı sınırlamaları azaltmak için tasarlanmıştır. Sınıfların ve niteliklerin birleşiminden doğan anlamlılık, karmaşıklığı azaltan ve çoklu kalıtım ve iç içeliklerle ilgili bilinen sorunlardan kaçınan bir yol izlenerek tanımlanmıştır.

Nitelikler sınıflara benzemekle birlikte işlevselliği gruplamak için daha bir ince elenip sık dokunarak tasarlanmıştır. Bir niteliği kendi içinde örneklemek mümkün değildir. Geleneksel kalıtıma bir ekleme olup yatay davranış düzenini, yani kalıtım gerekmeksizin sınıf üyesi olmayı mümkün kılar.

Örnek 1 Nitelik örneği

<?php
trait ezcReflectionReturnInfo {
    function 
getReturnType() { /*1*/ }
    function 
getReturnDescription() { /*2*/ }
}

class 
ezcReflectionMethod extends ReflectionMethod {
    use 
ezcReflectionReturnInfo;
    
/* ... */
}

class 
ezcReflectionFunction extends ReflectionFunction {
    use 
ezcReflectionReturnInfo;
    
/* ... */
}
?>

Öncelik sırası

Bir nitelikle gelen bir üye, bir temel sınıftan miras alınan bir üyenin yerine geçerse onu geçersiz kılar; sınıfın kendi üyeleri de niteliğin yerine geçerse onu geçersiz kılar.

Örnek 2 Öncelik sırası örneği

Temel sınıftan miras alınan yöntem, DünyaDe niteliğinden MerhabaDünyam içine yerleştirilen üye tarafından geçersizleştirilmektedir. MerhabaDünyam sınıfı içinde tanımlı yöntemler için de davranış aynıdır. Öncelik sırası şöyledir: Temel sınıftan alınan yöntemleri geçersizleştiren nitelikleri geçerli sınıfın yöntemleri geçersizleştirir.

<?php
class Temel {
    public function 
merhabaDe() {
        echo 
'Merhaba ';
    }
}

trait 
DünyaDe {
    public function 
merhabaDe() {
        
parent::merhabaDe();
        echo 
'Dünya!';
    }
}

class 
MerhabaDünyam extends Temel {
    use 
DünyaDe;
}

$o = new MerhabaDünyam();
$o->merhabaDe();
?>

Yukarıdaki örneğin çıktısı:

Merhaba Dünya!

Örnek 3 Bir diğer öncelik sırası örneği

<?php
trait MerhabaDünya {
    public function 
merhabaDe() {
        echo 
'Merhaba Dünya!';
    }
}

class 
DünyaYetmez {
    use 
MerhabaDünya;
    public function 
merhabaDe() {
        echo 
'Merhaba Evren!';
    }
}

$o = new DünyaYetmez();
$o->merhabaDe();
?>

Yukarıdaki örneğin çıktısı:

Merhaba Evren!

Çoklu Nitelikler

Çok sayıda nitelik bir sınıfın içine use deyiminde virgüllerle ayrılarak yerleştirilebilir.

Örnek 4 Çok sayıda niteliğin kullanımı

<?php
trait Merhaba {
    public function 
merhabaDe() {
        echo 
'Merhaba ';
    }
}

trait 
Dünya {
    public function 
dünyaDe() {
        echo 
'Dünya';
    }
}

class 
MerhabaDünyam {
    use 
MerhabaDünya;
    public function 
Bağır() {
        echo 
'!';
    }
}

$o = new MerhabaDünyam();
$o->merhabaDe();
$o->dünyaDe();
$o->Bağır();
?>

Yukarıdaki örneğin çıktısı:

Merhaba Dünya!

Çelişki Çözümleme

Bir yönteme aynı isme sahip iki nitelik yerleştirilirse çelişki açıkça çözümlenmediği takdirde ölümcül bir hataya sebep olur.

Aynı sınıfta kullanılan nitelikler arasındaki adlandırma çakışmasını çözümlemek için insteadof işleci birini seçmek amacıyla kullanılabilir.

Bu işlem yöntemi dışlamayı sağladığından as işleci yönteme takma ad eklemek için kullanılabilir. as işlecinin yöntemin ismini değiştirmediğini ve diğer yöntemleri etkilemediğini unutmayın.

Örnek 5 Çelişki çözümleme örneği

Bu örnekte, Talker A ve B niteliklerini kullanıyor. A ve B çakışan yöntemlere sahip olduğundan B niteliğinden smallTalk ve A niteliğinden bigTalk kullanılmaktadır.

Aliased_Talker ise B'nin bigTalk gerçeklenimini talk diye bir takma ad altında kullanmak için as işlecinden yararlanmaktadır.

<?php
trait {
    public function 
smallTalk() {
        echo 
'a';
    }
    public function 
bigTalk() {
        echo 
'A';
    }
}

trait 
{
    public function 
smallTalk() {
        echo 
'b';
    }
    public function 
bigTalk() {
        echo 
'B';
    }
}

class 
Talker {
    use 
A{
        
B::smallTalk insteadof A;
        
A::bigTalk insteadof B;
    }
}

class 
Aliased_Talker {
    use 
A{
        
B::smallTalk insteadof A;
        
A::bigTalk insteadof B;
        
B::bigTalk as talk;
    }
}
?>

Bilginize:

7.0 öncesinde, bir nitelikteki gibi, bir özelliği ayni isimli bir sınıf içinde tanımlamak, sınıf tanımı uyumlu ise (aynı görünürlük ve ilk değer), bir E_STRICT hatasına yol açar.

Yöntem Görünürlüğünü Değiştirme

Sergileyen sınıf içinde yöntemin görünürlüğünü ayarlamak için as sözdizimi kullanılabilir.

Örnek 6 Yöntem görünürlüğünü değiştirme örneği

<?php
trait MerhabaDünya {
    public function 
merhabaDe() {
        echo 
'Merhaba Dünya!';
    }
}

// merhabaDe görünürlüğünü değiştir
class Sınıfım1 {
    use 
MerhabaDünya merhabaDe as protected; }
}

// Görünürlüğü ve ismi değişmiş yöntem
// merhabaDe görünürlüğü değişmedi
class Sınıfım2 {
    use 
MerhabaDünya merhabaDe as private özelMerhabam; }
}
?>

Niteliklerden oluşturulmuş Nitelikler

Sınıflarda olduğu gibi nitelikler de bir diğerinin içinde kullanılabilir. Birden fazla nitelik kısmen veya tamamen bir diğer niteliğin içinde kullanılabilir.

Örnek 7 Niteliklerden nitelik oluşturma örneği

<?php
trait Merhaba {
    public function 
merhabaDe() {
        echo 
'Merhaba ';
    }
}

trait 
Dünya {
    public function 
dünyaDe() {
        echo 
'Dünya!';
    }
}

trait 
MerhabaDünya {
    use 
MerhabaDünya;
}

class 
MerhabaDünyam {
    use 
MerhabaDünya;
}

$o = new MerhabaDünyam();
$o->merhabaDe();
$o->dünyaDe();
?>

Yukarıdaki örneğin çıktısı:

Merhaba Dünya!

Soyut Nitelik Yöntemleri

Nitelikler, sergileyen sınıfa gereksinimleri aşılamak amacıyla yöntem soyutlamayı destekler.

Dikkat

Somut bir sınıf aynı adı taşıyan somut bir yöntemi tanımlayarak bu gerekliliğini yerine getirir; imzası farklı olabilir.

Örnek 8 Gereksinimlerin soyut yöntemlerle ifadesi

<?php
trait Merhaba {
    public function 
merhabaDünyaDe() {
        echo 
'Merhaba'.$this->dünyaGetir();
    }
    abstract public function 
dünyaGetir();
}

class 
MerhabaDünyam {
    private 
$dünya;
    use 
Merhaba;
    public function 
dünyaGetir() {
        return 
$this->dünya;
    }
    public function 
dünyaAta($val) {
        
$this->dünya $val;
    }
}
?>

Duruk Nitelik Yöntemleri

Nitelikler hem duruk üyeleri hem de duruk yöntemleri tanımlayabilir.

Örnek 9 Duruk Değişkenler

<?php
trait Sayaç {
    public function 
arttır() {
        static 
$c 0;
        
$c $c 1;
        echo 
"$c\n";
    }
}

class 
C1 {
    use 
Sayaç;
}

class 
C2 {
    use 
Sayaç;
}

$o = new C1(); $o->arttır(); // 1 basar
$p = new C2(); $p->arttır(); // 1 basar
?>

Örnek 10 Duruk Yöntemler

<?php
trait DurukÖrnek {
    public static function 
bişeyYap() {
        return 
'Bir şey yapıyorum';
    }
}

class 
Örnek {
    use 
DurukÖrnek;
}

Örnek::bişeyYap();
?>

Özellikler

Nitelikler özellik tanımlayabilir.

Örnek 11 Özellik tanımlama örneği

<?php
trait NitelikliÖzellik {
    public 
$x 1;
}

class 
ÖzellikÖrneği {
    use 
NitelikliÖzellik;
}

$örnek = new ÖzellikÖrneği;
örnek->x;
?>

Bir nitelik bir özellik tanımlarsa sınıf aynı isimde bir özellik (uyumlu - aynı görünürlük ve ilk değer - olmadıkça) tanımlayamaz, aksi takdirde bir hata oluşur. 7.0 öncesinde, bir nitelikteki gibi, bir özelliği ayni isimli bir sınıf içinde tanımlamak, sınıf tanımı uyumlu ise (aynı görünürlük ve ilk değer), bir E_STRICT hatasına yol açar.

Örnek 12 Çelişki yaratma örneği

<?php
trait NitelikliÖzellik {
    public 
$aynı true;
    public 
$farklı false;
}

class 
ÖzellikÖrneği {
    use 
NitelikliÖzellik;
    public 
$aynı true;   // PHP 7.0.0 ve sonrasında izin verilir; 
                           // öncesinde E_STRICT uyarısı alır.
    
    
public $farklı true// ölümcül hata
}
?>