Sihirli Yöntemler
  
   Sihirli yöntemler, bir nesne üzerinde belirli eylemler gerçekleştirildiğinde
   PHP'nin öntanımlı eylemini geçersiz kılan özel yöntemlerdir.
  
  Dikkat
   
    __ ile başlayan tüm yöntem isimleri PHP tarafından
    ayrılmıştır. Bu nedenle, PHP'nin davranışını geçersiz kılmadıkça bu tür
    yöntem adlarının kullanılması önerilmez.
   
   
  
   Aşağıdakiler sihirli yöntem olarak ele alınır:
   
   __construct(),
   __destruct(),
   __call(),
   __callStatic(),
   __get(),
   __set(),
   __isset(),
   __unset(),
   __sleep(),
   __wakeup(),
   __serialize(),
   __unserialize(),
   __toString(),
   __invoke(),
   __set_state(),
   __clone(),
   __debugInfo(),
   __clone() ve
   __debugInfo().
  
  
  Uyarı
   
    Bir sihirli yöntemin tanımında yapılan tür bildirimleri bu belgede
    açıklandığı gibi yapılmalıdır. Aksi takdirde, ölümcül hata çıktılanır.
    PHP 8.0.0 öncesinde hiçbir uyarı yapılmazdı.
    Bundan başka, __construct() ve
    __destruct() yöntemleri de
    bir dönüş türü bildirmemelidir, yoksa ölümcül hata oluşur.
   
   
  
   
   
   
   
    serialize() işlevi, sınıfın
    __sleep()
    adında sihirli bir işleve sahip olup olmadığına bakar. Böyle bir işlev
    varsa herhangi bir dizileştirme işleminden önce bu işlev çalıştırılır.
    Bu işlev ile nesne üzerinde temizlik yapılabilir ve dizileştirilmesi
    gereken nesnenin tüm değişken isimlerinin bir dizi halinde döndürülmesi
    sağlanabilir. Eğer işlev hiçbir şey döndürmemişse null
    dizileştirilir ve bir E_NOTICE çıktılanır.
   
   Bilginize: 
    
     Ebeveyn sınıflardaki private özelliklerin isimlerini döndürmek
     __sleep() için imkansızdır. Bu
     yapılırsa E_NOTICE seviyesinde bir hata
     iletisi çıktılanır. Bunun yerine Serializable
     arayüzünü kullanılabilir.
    
   
   Bilginize: 
    
     PHP 8.0.0 ve sonrasında, __sleep()
     işlevinden dizi olmayan bir değerin döndürülmesi uyarı üretimine sebep olur.
     Evvelce, bildirim üretimine sebep oluyordu.
    
   
   
    __sleep() işlevinin asıl kullanım
    amacı askıdaki veriyi göndermek gibi temizliğe benzer işlemler yapmaktır.
    Ayrıca, tümüyle kaydedilmesi gerekmeyen büyük bir nesne sözkonusu
    olduğunda da bu işlevden yararlanılabilir.
   
   
    unserialize() işlevi tersine bir işlem yaparak
    __wakeup() adında bir sihirli
    işlevin varlığını araştırır.
    Böyle bir işlev varsa, bu işlev nesnenin sahip olduğu tüm özkaynakları
    yeniden oluşturabilir.
   
   
    __wakeup() işlevinin asıl kullanım
    amacı, dizileştirme sırasında kaybedilebilen veritabanı bağlantılarını
    yeniden oluşturmak ve diğer ilklendirme işlemlerini yeniden yapmaktır.
   
   
    Örnek 1 - Uyutma ve uyandırma
    
<?php
class Bağlantı
{
    protected $hat;
    private $dsn, $kullanıcı, $parola, $db;
    public function __construct($dsn, $kullanıcı, $parola, $db)
    {
        $this->dsn = $dsn;
        $this->kullanıcı = $kullanıcı;
        $this->parola = $parola;
        $this->db = $db;
        $this->bağlan();
    }
    private function bağlan()
    {
        $this->hat = new PDO($this->dsn, $this->kullanıcı, $this->parola);
    }
    public function __sleep()
    {
       return array('dsn', 'kullanıcı', 'parola');
    }
    public function __wakeup()
    {
        $this->bağlan();
    }
}?>
     
    
   
  
   
   
    public __serialize(): 
array 
   
   
    serialize() işlevi, sınıfın
    __serialize() sihirli adına
    sahip bir işlevinin olup olmadığına bakar. Varsa, bu işlev herhangi
    bir dizileştirmeden önce çalıştırılır. Nesnenin dizileştirilmiş biçimini
    temsil eden ilişkisel bir anahtar/değer çiftleri dizisi oluşturmalı ve
    döndürmelidir. Hiçbir dizi döndürülmezse, bir
    TypeError yavrulanır.
   
   Bilginize: 
    
     Aynı nesnede hem __serialize()
     hem de __sleep() tanımlanmışsa,
     sadece __serialize()
     çağrılır. __sleep() ise yok
     sayılır. Nesne Serializable
     arayüzünü gerçekliyorsa, arayüzün serialize() yöntemi
     yok sayılır ve yerine __serialize()
     kullanılır.
    
   
   
    __serialize() yönteminin
    amaçlanan kullanımı, nesnenin dizileştirmeye uygun keyfi bir gösterimini
    tanımlamaktır. Dizinin öğeleri, nesnenin özelliklerine karşılık gelebilir,
    ancak bu gerekli değildir.
   
   
    unserialize() işlevi ise tersine sınıfın
    __unserialize() sihirli adına
    sahip bir işlevinin olup olmadığına bakar. Varsa, bu işlev
    __serialize() işlevinden
    döndürülen geri yüklenmiş diziye aktarılır. Daha sonra nesnenin
    özelliklerini uygun şekilde bu diziden geri yükleyebilir.
   
   Bilginize: 
    
     Aynı nesnede hem __unserialize()
     hem de __wakeup() tanımlanmışsa,
     yalnızca __unserialize()
     çağrılır. __wakeup() ise yok sayılır.
    
   
   Bilginize: 
    
     Özellik PHP 7.4.0'dan beri kullanılabilmektedir.
    
   
   
    Örnek 2 - Dizileştirme ve Nesneleştirme
    
<?php
class Connection
{
    protected $link;
    private $dsn, $username, $password;
    public function __construct($dsn, $username, $password)
    {
        $this->dsn = $dsn;
        $this->username = $username;
        $this->password = $password;
        $this->connect();
    }
    private function connect()
    {
        $this->link = new PDO($this->dsn, $this->username, $this->password);
    }
    public function __serialize(): array
    {
        return [
          'dsn' => $this->dsn,
          'user' => $this->username,
          'pass' => $this->password,
        ];
    }
    public function __unserialize(array $data): void
    {
        $this->dsn = $data['dsn'];
        $this->username = $data['user'];
        $this->password = $data['pass'];
        $this->connect();
    }
}?>
     
    
   
  
   
   
   
    __toString() yöntemi, sınıf bir
    dizgeye dönüştürüldüğünde sınıfın nasıl tepki vereceğine karar vermeyi
    sağlar. Örneğin, echo $obj; ile ne basılacağı gibi.
   
   Uyarı
    
     PHP 8.0.0'dan itibaren, dönüş değerine standart PHP tür anlamlandırması
     uygulanmaktadır, yani
     katı kodlama
     devre dışı bırakılırsa, mümkün olduğu takdirde değer string
     türe zorlanır.
    
    
     strict typing
     etkinken Stringable nesnesi
     string tür bildirimi tarafından kabul edilmez.
     Bunun olması isteniyorsa Stringable ve
     string türleri birleşim türü bildirimi içinde
     birleştirilmelidir.
    
    
     PHP 8.0.0'dan itibaren, __toString()
     yöntemi içeren her sınıf örtük olarak
     Stringable arayüzünü de gerçekler ve
     dolayısıyla bu arayüz için tür sınamaları yapılmaz. Bu durumda,
     arayüzün doğrudan gerçeklenmesi tercih edilmelidir.
    
    
     PHP 7.4'te, döndürülen değer mutlaka
     string türünde olmalıdır, aksi takdirde bir
     Error yavrulanır.
    
    
     PHP 7.4.0 öncesinde, döndürülen değer mutlaka
     string türünde olmalıydı, aksi takdirde ölümcül bir
     E_RECOVERABLE_ERROR çıktılanırdı.
    
    
   Uyarı
    
     __toString() yönteminin içinden
     bir istisna yavrulatılamaz. PHP 7.4.0 öncesinde, bunun yapılması ölümcül
     hata ile sonuçlanırdı.
    
    
   
    Örnek 3 - Basit bir örnek
    
<?php
// Basit bir sınıf tanımlayalım
class TestClass
{
    public $foo;
    public function __construct($foo)
    {
        $this->foo = $foo;
    }
    public function __toString()
    {
        return $this->foo;
    }
}
$class = new TestClass('Merhaba');
echo $class;
?>
     
    
Yukarıdaki örneğin çıktısı:
 
   
  
   
   
    __invoke(
 ...$values): 
mixed 
   
    __invoke() yöntemi, bir betik bir
    nesneyi bir işlev olarak çağırmaya çalışırsa çağrılır.
   
   
    Örnek 4 - __invoke() kullanımı
    
<?php
class CallableClass
{
  public function __invoke($x)
  {
    var_dump($x);
  }
}
$obj = new CallableClass;
$obj(5);
var_dump(is_callable($obj));
?>
     
    
Yukarıdaki örneğin çıktısı:
 
   
    Örnek 5 - __invoke() kullanımı
    
<?php
class Sort
{
    private $key;
    public function __construct(string $key)
    {
        $this->key = $key;
    }
    public function __invoke(array $a, array $b): int
    {
        return $a[$this->key] <=> $b[$this->key];
    }
}
$müşteriler = [
    ['no' => 1, 'isim' => 'John', 'soyisim' => 'Do'],
    ['no' => 3, 'isim' => 'Alice', 'soyisim' => 'Gustav'],
    ['no' => 2, 'isim' => 'Bob', 'soyisim' => 'Filipe']
];
// $müşterileri isme göre sırala
usort($müşteriler, new Sort('isim'));
print_r($müşteriler);
// $müşterileri soyisme göre sırala
usort($müşteriler, new Sort('soyisim'));
print_r($müşteriler);
?>
     
    
Yukarıdaki örneğin çıktısı:
Array
(
    [0] => Array
        (
            [no] => 3
            [isim] => Alice
            [soyisim] => Gustav
        )
    [1] => Array
        (
            [no] => 2
            [isim] => Bob
            [soyisim] => Filipe
        )
    [2] => Array
        (
            [no] => 1
            [isim] => John
            [soyisim] => Do
        )
)
Array
(
    [0] => Array
        (
            [no] => 1
            [isim] => John
            [soyisim] => Do
        )
    [1] => Array
        (
            [no] => 2
            [isim] => Bob
            [soyisim] => Filipe
        )
    [2] => Array
        (
            [no] => 3
            [isim] => Alice
            [soyisim] => Gustav
        )
)
 
    
   
  
   
   
   
    Bu statik yöntem,
    var_export() tarafından ihraç edilen
    sınıflar için çağrılır.
   
   
    Bu yöntemin tek bağımsız değişkeni
    ['özellik' =>
    değer, ...]
    biçeminde ihraç edilen özellikleri içeren bir dizidir.
   
   
    Örnek 6 - __set_state() kullanımı
    
    
<?php
class A
{
    public $var1;
    public $var2;
    public static function __set_state($bir_dizi)
    {
        $obj = new A;
        $obj->var1 = $bir_dizi['var1'];
        $obj->var2 = $bir_dizi['var2'];
        return $obj;
    }
}
$a = new A;
$a->var1 = 5;
$a->var2 = 'foo';
$b = var_export($a, true);
var_dump($b);
eval('$c = ' . $b . ';');
var_dump($c);
?>
     
    
Yukarıdaki örneğin çıktısı:
string(60) "A::__set_state(array(
   'var1' => 5,
   'var2' => 'foo',
))"
object(A)#2 (2) {
  ["var1"]=>
  int(5)
  ["var2"]=>
  string(3) "foo"
}
 
    
   Bilginize: 
    
     Bir nesne ihraç edilirken, var_export() işlevi
     __set_state() nesnenin sınıfı
     tarafından gerçeklenmiş mi diye bakmaz,  dolayısıyla böyle nesnelerin
     yeniden ithali __set_state() hiç gerçeklenmemiş gibi bir
     Error istisnası yavrulanmasına sebep olur.
     Bu kısmen bazı dahili sınıfları da etkiler.
    
    
     Sadece, __set_state() gerçekleyen sınıfın nesnelerinin yeniden ithal
     edilmesini sağlamak yazılımcının sorumluluğundadır.
    
   
   
  
   
   
   
    Gösterilmesi gereken özelliklerini döndürmek için bir nesne
    dökümleneceği zaman bu yöntem var_dump() tarafından
    çağrılır.
   
   
    Örnek 7 - __debugInfo()
      kullanımı
    
<?php
class C {
    private $prop;
    public function __construct($val) {
        $this->prop = $val;
    }
    public function __debugInfo() {
        return [
            'propSquared' => $this->prop ** 2,
        ];
    }
}
var_dump(new C(42));
?>
     
    
Yukarıdaki örneğin çıktısı:
object(C)#1 (1) {
  ["propSquared"]=>
  int(1764)
}