SmartObject
SmartObject nesnelerin davranışını birçok yönden düzeltirdi, ancak günümüz PHP'si bu iyileştirmelerin çoğunu zaten yerel olarak içermektedir. Bununla birlikte, hala property için destek ekler.
Kurulum:
composer require nette/utils
Özellikler, Getiriciler ve Ayarlayıcılar
Modern nesne yönelimli dillerde (örneğin C#, Python, Ruby, JavaScript) property terimi, sınıfların değişken gibi görünen ancak aslında yöntemlerle temsil edilen özel üyelerini ifade eder. Bu “değişkenin” değeri atandığında veya okunduğunda, ilgili yöntem (getter veya setter olarak adlandırılır) çağrılır. Bu çok kullanışlı bir şeydir, bize değişkenlere erişim üzerinde tam kontrol sağlar. Girdiyi doğrulayabilir veya yalnızca özellik okunduğunda sonuç üretebiliriz.
PHP özellikleri desteklenmez, ancak trait Nette\SmartObject
bunları taklit edebilir. Nasıl kullanılır?
- Sınıfa şu biçimde bir ek açıklama ekleyin
@property <type> $xyz
getXyz()
veyaisXyz()
adında bir getter, adında bir setter oluşturun.setXyz()
- Getter ve setter public veya protected olmalıdır ve isteğe bağlıdır, bu nedenle read-only veya write-only özelliği olabilir
$radius
değişkenine yalnızca negatif olmayan sayıların girilmesini sağlamak için Circle sınıfının
özelliğini kullanacağız. public $radius
öğesini özellik ile değiştirin:
/**
* @property float $radius
* @property-read bool $visible
*/
class Circle
{
use Nette\SmartObject;
private float $radius = 0.0; // herkese açık değil
//radius özelliği için getter
protected function getRadius(): float
{
return $this->radius;
}
//radius özelliği için setter
protected function setRadius(float $radius): void
{
// kaydetmeden önce değeri sanitize etme
$this->radius = max(0.0, $radius);
}
// özellik için getter $visible
protected function isVisible(): bool
{
return $this->radius > 0;
}
}
$circle = new Circle;
$circle->radius = 10; // aslında setRadius(10) çağırır
echo $circle->radius; // getRadius() işlevini çağırır
echo $circle->visible; // isVisible() işlevini çağırır
Özellikler öncelikle sözdizimsel şeker olup, kodu basitleştirerek programcının hayatını daha tatlı hale getirmeyi amaçlar. Eğer onları istemiyorsanız, kullanmak zorunda değilsiniz.
Tarihe Bir Bakış
SmartObject, nesnelerin davranışlarını çeşitli şekillerde iyileştirmek için kullanılırdı, ancak bugünün PHP'si bu geliştirmelerin çoğunu zaten yerel olarak içeriyor. Aşağıdaki metin geçmişe nostaljik bir bakıştır ve bize işlerin nasıl geliştiğini hatırlatır.
PHP'nin nesne modeli, başlangıcından itibaren sayısız ciddi eksiklik ve yetersizlikten muzdaripti. Bu durum, bu sorunları
gidermeyi ve PHP'nin kullanım rahatlığını artırmayı amaçlayan Nette\Object
sınıfının (2007'de)
oluşturulmasına yol açtı. İhtiyaç duyulan tek şey diğer sınıfların bu sınıftan miras almasıydı ve onlar da bu
sınıfın sunduğu avantajlardan yararlanabileceklerdi. PHP 5.4 özellikler için destek sunduğunda, Nette\Object
sınıfının yerini Nette\SmartObject
özelliği aldı. Bu, ortak bir atadan miras alma ihtiyacını ortadan
kaldırdı. Dahası, özellik zaten başka bir sınıftan miras alan sınıflarda kullanılabiliyordu. Nette\Object
'un kesin sonu, sınıfların Object
olarak adlandırılmasını yasaklayan PHP 7.2'nin yayınlanmasıyla geldi.
PHP'nin gelişimi devam ettikçe, nesne modeli ve dil yetenekleri de gelişti. SmartObject
sınıfının çeşitli
işlevleri gereksiz hale geldi. PHP 8.2'nin yayınlanmasından bu yana, PHP'de doğrudan desteklenmeyen tek bir özellik kaldı:
sözde özellikleri kullanma yeteneği.
Nette\Object
ve buna bağlı olarak Nette\SmartObject
hangi özellikleri sunuyordu? İşte genel bir
bakış. (Örneklerde Nette\Object
sınıfı kullanılmıştır, ancak çoğu özellik Nette\SmartObject
özelliği için de geçerlidir).
Tutarsız Hatalar
PHP, bildirilmemiş üyelere erişirken tutarsız davranışlar sergiliyordu. Nette\Object
adresinin durumu
aşağıdaki gibiydi:
echo $obj->undeclared; // E_NOTICE, daha sonra E_WARNING
$obj->undeclared = 1; // raporlama yapmadan sessizce geçer
$obj->unknownMethod(); // Ölümcül hata (try/catch ile yakalanamaz)
Ölümcül hata, herhangi bir tepki verme imkanı olmadan uygulamayı sonlandırdı. Var olmayan üyelere uyarı vermeden
sessizce yazmak, tespit edilmesi zor ciddi hatalara yol açabilirdi. Nette\Object
Tüm bu durumlar yakalandı ve bir
istisna MemberAccessException
atıldı.
echo $obj->undeclared; // throw Nette\MemberAccessException
$obj->undeclared = 1; // throw Nette\MemberAccessException
$obj->unknownMethod(); // throw Nette\MemberAccessException
PHP 7.0'dan beri PHP artık yakalanamayan ölümcül hatalara neden olmamaktadır ve bildirilmemiş üyelere erişim PHP 8.2'den beri bir hatadır.
Ne demek istiyorsun?
Bir nesne değişkenine erişirken veya bir yöntemi çağırırken yapılan yazım hatası nedeniyle
Nette\MemberAccessException
hatası atıldığında, Nette\Object
hata mesajında hatanın nasıl
düzeltileceğine dair ikonik “demek istediniz mi?” eki şeklinde bir ipucu vermeye çalışmıştır.
class Foo extends Nette\Object
{
public static function from($var)
{
}
}
$foo = Foo::form($var);
// throw Nette\MemberAccessException
// "Call to undefined static method Foo::form(), did you mean from()?"
Günümüz PHP'sinde “demek istediniz mi?” özelliği olmasa da, bu ifade Tracy tarafından hatalara eklenebilir. Hatta bu tür hataları otomatik olarak düzeltebilir.
Uzatma yöntemleri
C#'ın uzantı yöntemlerinden esinlenilmiştir. Mevcut sınıflara yeni yöntemler ekleme imkanı verdiler. Örneğin, kendi
DateTimePicker'ınızı eklemek için bir forma addDateTime()
yöntemini ekleyebilirsiniz.
Form::extensionMethod(
'addDateTime',
fn(Form $form, string $name) => $form[$name] = new DateTimePicker,
);
$form = new Form;
$form->addDateTime('date');
Uzatma yöntemlerinin pratik olmadığı kanıtlandı çünkü isimleri editörler tarafından otomatik olarak tamamlanmadı, bunun yerine yöntemin mevcut olmadığını bildirdiler. Bu nedenle destekleri kesilmiştir.
Sınıf Adını Alma
$class = $obj->getClass(); // using Nette\Object
$class = $obj::class; // PHP 8.0'dan beri
Yansıma ve Ek Açıklamalara Erişim
Nette\Object
getReflection()
ve getAnnotation()
yöntemlerini kullanarak yansıtma ve ek
açıklamaya erişim sundu:
/**
* @author John Doe
*/
class Foo extends Nette\Object
{
}
$obj = new Foo;
$reflection = $obj->getReflection();
$reflection->getAnnotation('author'); // 'John Doe' döndürür
PHP 8.0'dan itibaren meta-bilgilere öznitelikler şeklinde erişmek mümkündür:
#[Author('John Doe')]
class Foo
{
}
$obj = new Foo;
$reflection = new ReflectionObject($obj);
$reflection->getAttributes(Author::class)[0];
Yöntem Getiriciler
Nette\Object
metotları değişkenlermiş gibi ele almak için zarif bir yol sundu:
class Foo extends Nette\Object
{
public function adder($a, $b)
{
return $a + $b;
}
}
$obj = new Foo;
$method = $obj->adder;
echo $method(2, 3); // 5
PHP 8.1'den itibaren, birinci sınıf çağrılabilir sözdizimi olarak adlandırılan sözdizimini:https://www.php.net/…lable_syntax kullanabilirsiniz:
$obj = new Foo;
$method = $obj->adder(...);
echo $method(2, 3); // 5
Etkinlikler
Nette\Object
olayı tetiklemek için sözdizimsel
şeker sundu:
class Circle extends Nette\Object
{
public array $onChange = [];
public function setRadius(float $radius): void
{
$this->onChange($this, $radius);
$this->radius = $radius;
}
}
$this->onChange($this, $radius)
kodu aşağıdakine eşdeğerdir:
foreach ($this->onChange as $callback) {
$callback($this, $radius);
}
Netlik açısından sihirli yöntemden kaçınmanızı öneririz $this->onChange()
. Pratik bir ikame Nette\Utils\Arrays::invoke fonksiyonudur:
Nette\Utils\Arrays::invoke($this->onChange, $this, $radius);