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;
/* ... */
}
?>
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!
Ç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 Merhaba, Dü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!
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 niteliklerin birini dışlamayı sağladığından diğerini de farklı bir isimle içermek için as işleci kullanılabilir.
Ö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 A {
public function smallTalk() {
echo 'a';
}
public function bigTalk() {
echo 'A';
}
}
trait B {
public function smallTalk() {
echo 'b';
}
public function bigTalk() {
echo 'B';
}
}
class Talker {
use A, B {
B::smallTalk insteadof A;
A::bigTalk insteadof B;
}
}
class Aliased_Talker {
use A, B {
B::smallTalk insteadof A;
A::bigTalk insteadof B;
B::bigTalk as talk;
}
}
?>
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; }
}
?>
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 Merhaba, Dü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!
Nitelikler, sergileyen sınıfa gereksinimleri aşılamak amacıyla yöntem soyutlamayı destekler.
Ö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;
}
}
?>
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();
?>
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
tanımlayamaz, aksi takdirde bir hata oluşur. Eğer sınıf tanımı (aynı
görünürlük ve ilk değer olarak) uyumluysa E_STRICT
çıktılanır değilse ölümcül bir hata oluşur.
Ö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; // Strict
public $farklı = true; // ölümcül hata
}
?>