Sihirli yöntemler, bir nesne üzerinde belirli eylemler gerçekleştirildiğinde PHP'nin öntanımlı eylemini geçersiz kılan özel yöntemlerdir.
__
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().
__construct(),
__destruct() ve
__clone() hariç tüm sihirli yöntemler
mutlaka public
olarak
bildirilmelidir, aksi takdirde bir E_WARNING
çıktılanır. PHP 8.0.0 öcesinde,
__sleep(),
__wakeup(),
__serialize(),
__unserialize() ve
__set_state() sihirli yöntemleri
için böyle bir uyarı yapılmazdı.
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 bir hata çıktılanır. PHP 8.0.0 öncesinde hiçbir uyarı yapılmazdı.
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.
__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 veri parçaları 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->connect();
}
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();
}
}?>
$data
) : voidserialize() 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.
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.
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ı.
__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ı:
Merhaba
__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ı:
int(5) bool(true)
$özellikler
) : objectBu statik yöntem, var_export() tarafından ihraç edilen sınıflar için çağrılır.
Bu yöntemin tek değiştirgesi ['
özellik' =>
değer,
...]
biçeminde ihraç edilen özellikleri içeren bir dizidir.
Örnek 5 - __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, __set_state() nesnenin sınıfı tarafından gerçeklenmiş mi diye var_export() bakmaz, dolayısıyla böyle nesnelerin yeniden ithali __set_state() hiç gerçeklenmemiş gibi başarısız olur. Bu kısmen bazı dahili sınıfları da etkiler. Sadece, __set_state() gerçekleyen sınıfın nesnelerinin yeniden ithal edileceğini doğrulamak 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 6 - __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) }