Kişisel bir web günlüğü

PHP 5′de metot zincirleme

phpPhp'nin 5. sürümü gerçekten bir çok yenilikle gelmişti ve özellikle bu yenilikler nesneye yönelik programlama (oop) ile ilgiliydi. Yeniliklerden birisi de bu yazıda bahsedecek olduğum "method chaining" yani "metot zincirleme" özelliği. Bu özellik sayesinde sınıf içerisindeki metotlar, o anki nesneyi geriye döndürebiliyor ve böylelikle metotlar birbirlerine bağlanabiliyorlar. Bu sayede daha pratik ve göze hoş gelen bir kodmaya yapabiliyoruz.

$sinif->metod1()->metod2()->metod3()->metod4()->metod5()....

Metot zincirlemeye giriş...

Konuya bir örnek üzerinde anlatarak devam edelim. Bir kişinin doğum tarihini girebileceğimiz ve bu doğum tarihini ekrana yazdıran "dogumTarihi" isminde bir sınıfımız olsun. Sınıfı oluşturan kodlar şöyle:

  1. class dogumTarihi{
  2.  
  3.     private $gun;
  4.     private $ay;
  5.     private $yil;
  6.  
  7.     public function girGun($gun){
  8.         $this->gun = $gun;
  9.     }
  10.  
  11.     public function girAy($ay){
  12.         $this->ay = $ay;
  13.     }   
  14.    
  15.     public function girYil($yil){
  16.         $this->yil = $yil;
  17.     }
  18.    
  19.     public function yazdir(){
  20.         printf(
  21.             'Girilen doğum tarihi: %u.%u.%u',
  22.             $this->gun, $this->ay, $this->yil
  23.         );
  24.     }
  25. }

Eğer bu sınıfı çağırıp kullansaydık kodlarımız şöyle olacaktı:

  1. $dt = new dogumTarihi();
  2. $dt->girGun(28);
  3. $dt->girAy(8);
  4. $dt->girYil(1980);
  5. $dt->yazdir();

Gördüğünüz gibi bütün metotları kullanabilmek için "$dt->" ifadesini yazarak, o anki nesneyi tekrar tekrar "biz" çağırmak zorunda kalıyoruz. Oysaki php 5’de metot zincirleme yaptığımızda, metotları "grup" halinde çağırabiliriz ve bu sınıfı daha pratik bir şekilde kullanabiliriz.

Metot zincirleme nasıl yapılıyor?

Kesinlikle çok kolay bir şekilde yapılıyor :) Php 5’de metotları birbirine bağlayabilmeniz için, bağlanacak metodun o anki nesneyi geri döndürmesi gerekmektedir. Bunu da return $this; ile yapabiliyoruz. Şimdi yukarıdaki "dogumTarihi" sınıfını, metot zincirlemeyi de göz önüne alarak yeniden yazalım:

  1. class dogumTarihi{
  2.  
  3.     private $gun;
  4.     private $ay;
  5.     private $yil;
  6.  
  7.     public function girGun($gun){
  8.         $this->gun = $gun;
  9.         return $this//dikkat
  10.     }
  11.  
  12.     public function girAy($ay){
  13.         $this->ay = $ay;
  14.         return $this//dikkat
  15.     }   
  16.    
  17.     public function girYil($yil){
  18.         $this->yil = $yil;
  19.         return $this//dikkat
  20.     }
  21.    
  22.     public function yazdir(){
  23.         printf(
  24.             'Girilen doğum tarihi: %u.%u.%u',
  25.             $this->gun, $this->ay, $this->yil
  26.         );
  27.     }
  28. }

Sınıfımızı bu şekilde düzenledikten sonra artık metotları birbirine bağlayarak "grup" halinde çağırabiliriz:

  1. $dt = new dogumTarihi();
  2. $dt->girGun(28)
  3.    ->girAy(8)
  4.    ->girYil(1980)
  5.    ->yazdir();

Sonuç

Dikkat ederseniz metot zincirlemeyi, normalde geriye bir değer döndürmesine gerek olmayan metotlarda kullanıyoruz. Bu metotlara "set methods" yani "atama metotları" adı veriliyor. Özetlersek; sınıf içerisine veri girmemizi sağlayan metotları birbirine bağlayarak, php 5’in bize sağladığı bu kolaylıktan faydalanabiliyoruz ;)

NOT: yazıda bahsedilen sınıfları ve bu sınıfların kullanılış örneklerini buradan bilgisayarınıza indirebilirsiniz.

17 Haziran 2009, 09:43 Programlama Bugün 3 kez, toplamda ise 2.884 kez okundu.
13 yorum var
  1. Ellerine sağlık.

  2. “fluent interface” tasarım stili olarak da geçiyor.

  3. @Kadir
    evet, teşekkürler. konu bütünlüğünü sağlamak açısından ona da link verelim:

    http://en.wikipedia.org/wiki/Fluent_interface#PHP

  4. tebrikler Erhan , yeniden ürettiğini görmek güzel :)

  5. Uzun bir aradan sonra, mükemmel bir makale…

  6. ara açılıyor bazen ama dönüş güzel oluyor :) ) teşekkürler.

  7. Şaban Ulutaş 25 Haziran 2009 08:54

    makale güzel. bugün yeni bi şey öğrendik sayende eburhan ;) yeri değil ama bi şey soracam; javam.org a girdiğim zaman sedo nun parking sayfası çıkıyor karşıma. bu konuda bir bilginiz varmı?

  8. Böyle kullanılabildiğini bilmiyordum teşekkürler.

  9. @Şaban
    javam.org yakında kendi sunucusuna taşınacak. Biraz beklemeniz gerekiyor.

  10. @Erhan: Siteni uzun süredir takip etmeme rağmen, yazdığım ilk yorum olacak, o yüzden öncelikle içerik için teşekkürler, ve tebrikler.

    Konu ile ilgili yoruma gelince, method chaining, kimi kodlama uygulamalarına (coding practice* demek istedim, iyisimi terimleri olduğu gibi bırakayım) haksız sayılmayacak şekilde sınırlı bir kullanımı olduğunu söylemekte -fakat tabii ki hayatı kolaylaştırmadığını söylemiyorum-, bunun nedeni bitirme problemi. Erhan’ın yazılarını takip edenlerin, jQuery’ye oldukça aşina olduklarını sanıyorum, bu problemin bir örneğini jQuery resmi manual’inde görebiliyoruz:

    $(‘#faq’).find(‘dd’).hide().end().find(‘dt’).click(function() {
    $(this).next().slideToggle();
    });
    }

    Bu kullanımda, end(); kod okunurluğu açısından baktığımızda bir öncesinde ve bir sonrasında kullanılan find() ‘ın ortasında oldukça gizemli bir iş yapıyora benziyor, ve chaining pratikte bozuluyor. Bunun nedeni objeye mudahale ederken uğraştığımız ‘context variable’ ‘lar.

    Başlangıçtaki objenin işleyişini değiştirmiş veya bir methodun temel bir değişkene mudahale etmesiyle pratikte başka bir objeyi döndürmeye zorunlu olmasından dolayı bize context i değişmemiş objeyi tekrar döndürecek bir methoda ihtiyaç duyuyoruz. Burada end(), en azından hiç değişmemiş olan objenin kopyasını döndürerek bir sonraki chain için sorguyu hazır hale getiriyor. Method Chaining yöntemini kullanmak istiyorsanız, bu end() benzeri (end() neredeyse her method chaining uygulamasında standart olarak kabul edilmiştir) methodunu da baştan tanımlamanız, bazı işleri ‘design pattern’ ‘in dışına çıkmadan tanımlamamızı sağlayacaktır.

    End methodunu kurgulamak içinse, ya class’ın construct overload methodunun, ya da contexti değiştiren methodun gerekli yedekleri almasını sağlamak ve end() methoduyla yedekteyi veriyi geri döndürmesini sağlamak yeterli.

    Yine de, kod okunurluğu açısından, böyle bir uygulama gerektirmeyecek, bütün işlemlerin objeye doğrudan etkisi olmadan, bütün fonksiyon çağrılarının sadece objenin parametrelerinin etrafında dönen işlemlerde method chaining’in tercih edilmesi daha yaygın bir kullanım. End() gerektirmeyecek PHP’de yaygın bir kullanım örneğini bir ‘query builder’ yaratarak elde edebiliriz:

    $res = $db->select(‘id’)->from(‘hede’)->where(‘x=y’)->get();

    gibi.

  11. @Gökçe YALÇIN
    Bilgilendirici yorumun için teşekkürler (senin gibi yorum yazanlara ihtiyaç var blogkürede).

  12. Güzel makale eline sağlık..


  13. class dogumTarihi{

    public $tarih;
    public static $_tarih;

    public function __call($key,$value)
    {
    foreach($value as $a=> $val)
    {
    $this->tarih[$key] = $val;
    }
    return $this;
    }

    public function yazdir()
    {

    foreach((array)$this as $key=> $val)
    {
    foreach($val as $a => $b)
    {
    echo $a.'='.$b.'';
    }
    }
    }

    public static function __callStatic($key,$value)
    {
    foreach($value as $a=> $val)
    {
    self::$_tarih[$key] = $val;
    }
    return self::$_tarih;
    }

    public static function yazdirs()
    {
    foreach((array)self::$_tarih as $key=> $val)
    {
    echo $key .'='.$val.'';
    }
    }

    }

    $dogumTarih = new dogumTarihi;
    $dogumTarih->gun(6)
    ->ay(11)
    ->yil(1984);
    $dogumTarih->yazdir();

    dogumTarihi::gun(6);
    dogumTarihi::ay(11);
    dogumTarihi::yil(1984);
    dogumTarihi::yazdirs();

    bu örneğimde php 5.0 ve php 5.3 de basit bir call sihirbaz çağırımı yöntemiyle zindirlemeye örnek.

İçinizde kalmasın, siz de yorum yazın

Telif Hakkı © 2010 eburhan.com | Structure | XHTML