SmartObject ve StaticClass

SmartObject PHP sınıflarına property desteği ekler. StaticClass statik sınıfları belirtmek için kullanılır.

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() veya isXyz() 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.

Statik Sınıflar

Statik sınıflar, yani örneklenmesi amaçlanmayan sınıflar, Nette\StaticClass özelliği ile işaretlenebilir:

class Strings
{
	use Nette\StaticClass;
}

Bir örnek oluşturmaya çalıştığınızda, sınıfın statik olduğunu belirten Error istisnası atılır.

Tarihe Bir Bakış

SmartObject eskiden sınıf davranışını birçok yönden geliştirir ve düzeltirdi, ancak PHP'nin evrimi orijinal özelliklerin çoğunu gereksiz hale getirdi. Bu nedenle aşağıda, işlerin nasıl geliştiğinin geçmişine bir bakış yer almaktadır.

PHP nesne modeli en başından beri bir dizi ciddi kusur ve verimsizlikten muzdaripti. Bu eksiklikleri gidermeye ve PHP kullanım deneyimini iyileştirmeye çalışan Nette\Object sınıfının (2007'de) yaratılmasının nedeni buydu. Diğer sınıfların bu sınıftan miras alması ve sağladığı avantajlardan yararlanması için yeterliydi. PHP 5.4 trait desteği ile geldiğinde, Nette\Object sınıfı Nette\SmartObject ile değiştirildi. Böylece artık ortak bir atadan miras almaya gerek kalmamıştı. Ayrıca, trait zaten başka bir sınıftan miras alan sınıflarda da kullanılabiliyordu. Nette\Object 'un nihai sonu, sınıfların Object olarak adlandırılmasını yasaklayan PHP 7.2 sürümüyle geldi.

PHP'nin gelişimi devam ettikçe, nesne modeli ve dil yetenekleri geliştirildi. SmartObject sınıfının bireysel işlevleri gereksiz hale geldi. PHP 8.2'nin yayınlanmasından bu yana, PHP'de henüz doğrudan desteklenmeyen tek özellik, sözde özellikleri kullanma yeteneğidir.

Nette\Object ve Nette\Object bir zamanlar hangi özellikleri sunuyordu? İşte genel bir bakış. (Örnekler Nette\Object sınıfını kullanmaktadır, ancak özelliklerin çoğu 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?” gibi bir ifade bulunmayabilir, ancak Tracy hatalara bu eki ekler. Ve bu tür hataları kendisi bile 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);
versiyon: 4.0