Php de bulunan özelliklerden biri de php magic methods. (Kendiliğinden çalışan da diyebiliriz türkçe olarak.)
Ne İşe Yarar Bu Magic Metodlar?
Magic metodlar, Class seviyesinde çalışan metodlardır. Örneğin aşağıdaki örnek için $deneme = new Deneme(); yazdığımızda Deneme sınıfındaki
__construct magic metodu çalışır. Tıpkı bunun gibi, classta olmayan bir metodu çağırdığınızda
__call() metodu çağrılır.
class Deneme { public function __construct(){ // } }
Php 5.3 itibariyle destek verdiği magic metodları listeleyelim.
php 5.3 magic methods
__construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __toString(), __invoke(), __set_state(), __clone()
__construct() :
Yukarıda da bahsettiğim gibi $deneme = new Deneme(); yazdığımızda ilk olarak çalışan metoddur. __construct metoduna parametre göndermek istiyorsak
$deneme = new Deneme($param1, $param2, ..);
şeklinde yapabiliriz. Tercihe bağlı olarak sınıf için bir nesne yarattığımızda, gerekli tanımlama (define) işlemleri, bağlantı kurma (örneğin veritabanı bağlantısı, ya da dosya açma) metodlarını çalıştırma, gibi işlemler için kullanılır. Önemli olan bir nokta, __construct metodumuzu private ya da protected olarak değil
public olarak tanımlamamız gerekir.
__destruct() :
Bu metod adından da açıkca belli olduğu üzere __construct metodunun aksine sınıf için nesne yaratıldığında değil değil sınıf sonlanırken çalışır. Sınıf sonlanırkenden kastım, sınıf içinde kullandığımız nesneleri unset(); ederken, veritabanı ile bağlantıyı kapatırken, ya da kullandığımız dosyayı kapatırken, log tutarken (Deneme sınıfı çalıştı, şu şu işlemler yapıldı, şu nesneler yok edildi) vb. işlemler için kullanılabilir.
Method Aşırı yükleme (Method Overloading)
__call() :
Erişilemeyen metod (ya da olmayan metod) nesne tarzında çağırıldıysa, __call metodu çalışır.
__callStatic() :
Erişilemeyen metod (ya da olmayan metod) statik tarzında çağırıldıysa __callStatic metodu çalışır. Deneme sınıfımız üzerinden örnek verecek olursam;
class Deneme{ public function __call($name, $arguments){ echo "$name metodu nesne olarak, şu parametelerle çalıştırılmak istendi: ".implode(',', $arguments); } public function __callStatic($name, $arguments){ echo "$name metodu statik olarak,şu parametelerle çalıştırılmak istendi: ".implode(',', $arguments); } }
Görüldüğü gibi iki metod da 2 parametre alıyor. İlki çalıştırılmak istenen metod ismi, ikincisi metod çağırılırken gönderilen parametreler. Yani biz sınıf dışından tanımlı olmayan, ya da tanımlı olup erişemediğimiz bir yerden, exec(); metodunu
$deneme->exec("admin", 5); şeklinde çalıştırmak istersek __call metodu,
Deneme::exec("admin", 5); şeklinde çalıştırmak istersek __callStatic metodu çalışır.
Aşırı yükleme (Overloading)
Overloading, dinamik olarak özellik ya da metod yaratmak anlamına gelir. Bu özellikleri ya da metodları kullanırken de magic metodlar üzerinden işlem yaparız. Örnek olarak Deneme sınıfının içerisinde bu metodları kullanıp daha sonra açıklamasını yapayım.
class Deneme{ /*Overload verileri burada topluyoruz*/ private $_data = array(); public $length = 25; private $width = 20; public function __set($name, $value){ echo "$name ozelligine $value degeri ataniyor\n"; $this->_data[$name] = $value; } public function __get($name){ if (array_key_exists($name, $this->_data)) { echo "$name ozelliginin degeri istendi: "; return $this->_data[$name]; } echo "__get ile tanimsiz ozellik istendi"; return null; } public function __isset($name){ echo "$name ozelliginin olup olmadigi : \n"; return isset($this->_data[$name]); } public function __unset($name){ echo "$name siliniyor\n"; unset($this->_data[$name]); } }
Çalıştırıldığında daha net görülebilmesi için yorum satırı olarak eklemek yerine hangi metodun ne iş yaptığını echo kullanarak göstermeyi tercih ettim.
__set() :
__set metodu, erişilebilir olmayan bir özelliğin
değerini değiştirmeye çalıştığımızda ya da bir özellik
oluşturmak istediğimizde iş görür. 2 parametre alır, ilki değişken ikincisi ise değer. Örneğin sınıf içerisinde olmayan bir $size özelliğini düşünelim. $deneme->size = 5; yazdığımızda, Deneme sınıfı içerisindeki önceden overload için tanımladığımız $_data arrayini kullanarak $_data[size] = 5; oluşturmuş oluruz. Sınıf içerisinde tanımlı olan private $width için $deneme->width = 10; olarak değerini değiştirmeye çalıştığımızda ise, eğer __set metodu varsa, özelliğin değerini değiştirebiliriz. Eğer __set metodu yoksa,
Cannot access private property... şeklinde bir
fatal error alırız.
__get() :
Sınıf içerisinde erişilebilir olmayan bir özelliğe
erişmeye çalıştığımıza __get metodu çalışır. Bu metod parametre olarak kullanmak istediğimiz elemanı alır. Sınıf içerisinde tanımlı olmayan bir $size özelliğini düşünelim. echo $deneme->size; yazdığımızda bize null değer döner. __get metodunu yazmamış olsaydık
Undefined property... şeklinde bir
notice alırdık. Sınıf içerisinde tanımlı olan public $length = 25; özelliğine bakalım. public olduğudan dolayı, yani sınıf dışarısından erişmemizde bir problem olmadığından dolayı
__get metodu çalışmaz, echo $deneme->length; yazdığımızda doğrudan değere ulaşırız. Önce __set metodunu kullanarak yeni bir özellik yaratıp ve buna değer atayıp, daha sona __get metodunu kullanarak bunu çağıralım;
$deneme->hacim = 5; echo $deneme->hacim;
Sayfada göreceğimiz çıktı şu olur;
hacim ozelligine 4 degeri ataniyor hacim ozelliginin degeri istendi 4
__isset() :
isset(); metodu normalde true ya da false olarak boolean tipte değer döndürür. Biz sınıf içerisinde yarattığımız bir özellik için isset(); kullanırsak, __isset(); magic metodumuz çalışır.
$deneme->hacim = 5; // __set kullanildi echo $deneme->hacim; //__get kullanildi var_dump(isset($deneme->hacim)); //__isset kullanildi
__unset() :
__unset metodu da, yarattığımız bu değişkenleri yok etmeye yarar.
$deneme->hacim = 5; // __set kullanildi echo $deneme->hacim; //__get kullanildi var_dump(isset($deneme->hacim)); //__isset kullanildi true döndü unset($deneme->hacim); //__unset kullanildi var_dump(isset($deneme->hacim)); // __isset kullanildi false döndü
Nesne saklama (Object Serialization)
__sleep() :
Sınıf için yarattığımız nesneyi serialize(); metodu ile kullandığımızda __sleep metodu devreye girer. __sleep metodu, nesnenin serialize olması istenen özelliklerini
array olarak geri döndürür. Serialize etmek, kullanılabilir bir örneğini saklamak anlamındadır. Serialize edilen nesne text dosyasında ya da veritabanında vb. saklanabilir.
__wakeup() :
unserialize(); metodunu kullandığımızda çalışan metoddur. __sleep metodunun tam tersi işlevi yapar, saklanan veriyi ortaya çıkartır. Basitçe kullanımlarını örnekleyelim;
class Deneme{ public $name; public $age; public function __construct($name, $age){ $this->name = $name; $this->age = $age; } public function __sleep(){ echo "Serialize ediliyor: "; return array('name', 'age'); } public function __wakeup(){ echo "Unserialize ediliyor: "; } } $deneme = new Deneme("Gokhan", 20); $a = serialize($deneme); // serialize ettik var_export($a); // serialize edilmiş halini gördük /* deneme.txt adında bir dosyaya yazalım, daha sonra da aynı dosyadan okuyalım*/ $fptr = fopen("deneme.txt", "w"); fwrite($fptr, $a); fclose($fptr); $s = implode('', file("deneme.txt")); $s = unserialize($s); //unserialize ettik var_export($s); //unserialize edilmiş halini görelim
Serialize edilmiş hal text dosyasında şu şekilde saklanır;
O:6:"Deneme":2:{s:4:"name";s:6:"Gokhan";s:3:"age";i:20;}
Nesnelerle string işlemleri
__toString() :
Bu metod, sınıf için yarattığımız nesneyi yazdırmak istediğimizde, yani echo yapmak istediğimizde çalışan metoddur.
class Deneme{ public $name; public function __construct($name){ $this->name = $name; } public function __toString(){ return $this->name; } } $deneme = new Deneme('Dubluve'); echo $deneme;
Ekranda
Dubluve'yi görürüz. __toString metodunu kullanmadan nesneyi yazdırmaya çalışırsak
Catchable fatal error: Object of class Deneme could not be converted to string... ile karşılaşırız.
__set_state() :
Bu metod, sınıfımıza oluşturduğumuz nesne için var_export(); metodu kullanıldığında çalışır. var_export metodunun ne işe yaradığını bilmiyorsanız
buradan inceleyebilirsiniz. __set_state metodu parametre olarak nesnenin kendisini array olarak alır. Örnekleyecek olursak
class Deneme{ private $_var1; private $_var2; public function __construct(){ $this->_var1 = 100; $this->_var2 = 200; } public static function __set_state(array $array){ foreach ($array as $key => $value) { echo "$key ==> $value"; } } } $deneme = new Deneme(); eval(var_export($deneme, true).';');
Bize sonuç olarak şunu verir;
_var1 ==> 100 _var2 ==> 200
Eğer
__set_state metodunu tanımlamadan var_export($deneme, true); kullanırsak
Deneme::__set_state(array( '_var1' => 100, '_var2' => 200, ))
sonucu ile karşılaşırız.
Nesneyi fonksiyon olarak kullanmak
__invoke() :
Bir nesneyi bir metod olarak çağırdığımızda çalışan metoddur. Şöyle ki,
class Deneme{ public function __invoke($var){ var_dump($var); } } $deneme = new Deneme(); $deneme(5); // $deneme->__invoke(5);
Eğer __invoke metodunu kullanmadan nesneyi metodmuş gibi kullanmaya çalışırsak,
Fatal error: Function name must be a string... ile karşılaşırız.
Nesne kopyalamak (clone)
__clone() :
İsminden de belli olduğu gibi klonlamak, kopyalamak temeline dayanan magic metodumuz. Örnek üzerinden anlatmak en güzeli olacak. İlk olarak __clone kullanmadan bir nesneyi diğer nesneye nasıl kopyalarız buna bi bakalım.
class Deneme{ public $name; public $age; } $ogrenci_1 = new Deneme(); $ogrenci_1 -> name = "Gokhan"; $ogrenci_1 -> age = 20; $ogrenci_2 = $ogrenci_1; $ogrenci_2 -> name = "Osman"; $ogrenci_2 -> age = 23; var_export($ogrenci_1); var_export($ogrenci_2);
Deneme sınıfımızda sadece 2 tane özellik tanımladım.
$name ve
$age. İlk nesnemiz
$ogrenci_1 içine bu özellikleri yerleştirdik, daha sonra
$ogrenci_1 nesnemizi $ogrenci_2 nesnesine atadım (assign) ve ona da farklı özellikleri yerleştirdik. Fakat var_export kullanıp sonuçlara baktığımızda şöyle bir tabloyla karşılaşırız;
Deneme::__set_state(array( 'name' => 'Osman', 'age' => 23, )) Deneme::__set_state(array( 'name' => 'Osman', 'age' => 23, ))
Bunun sebebi, $ogrenci_2 nesnesi üzerinde yaptıklarımızın $ogrenci_1 nesnesini de etkilemesidir. Çünkü
2 nesne de aynı hafıza konumunu işaret ediyorlar. Şimdi gelelim __clone kullanımına. Aynı örneği __clone kullanarak yapalım.
class Deneme{ public $name; public $age; public function __clone(){ echo "Nesne kopyalandi\n"; } } $ogrenci_1 = new Deneme(); $ogrenci_1 -> name = "Gokhan"; $ogrenci_1 -> age = 20; $ogrenci_2 = clone $ogrenci_1; $ogrenci_2 -> name = "Osman"; $ogrenci_2 -> age = 23; var_export($ogrenci_1); var_export($ogrenci_2);
Burada
clone keywordunu kullandık (
$ogrenci_2 = clone $ogrenci_1;), clone keywordu __clone metodunun çalışmasını sağladı. __clone metodu içinde özellikleri de clone yapabiliriz. Sonucu :
Nesne kopyalandı Deneme::__set_state(array( 'name' => 'Gokhan', 'age' => 20, )) Deneme::__set_state(array( 'name' => 'Osman', 'age' => 23, ))
Devamı için :
php magic methods