# PHP 8.2 yolda: readonly sınıflar ve yeni tipler

> PHP 8.2 ile gelen readonly sınıflar, DNF tipler ve tek başına tip bildirimleri; bu eklemelerin domain modellemesine etkisi.

- Yayın: 2022-11-06
- Kategori: Diller
- Etiketler: PHP
- Okuma süresi: 3 dk okuma
- Kaynak: https://www.muhammetsafak.com.tr/blog/php-8-2-yolda-readonly-siniflar-ve-yeni-tipler/
- Dil: tr-TR
- Yazar: Muhammet Şafak

---
PHP 8.2'nin yıl sonunda yayımlanmasını bekliyorum. Bu yazıyı sürüm henüz çıkmadan, RFC'leri ve beta paketini inceleyerek yazıyorum — çünkü 8.2, mütevazı başlıklarına rağmen benim için anlamlı bir şeyi kolaylaştırıyor: immutability'yi sınıf düzeyinde ifade etmeyi.

## readonly sınıflar

[PHP 8.1 ile **readonly property** gelmişti](/blog/php-8-1-yolda-enumlar-ve-readonly-ile-daha-guvenli-modeller): bir özelliği yalnızca bir kez, kurucu metot içinde atayabiliyordunuz. İşe yarıyordu ama on alanlı bir value object'te her alanın başına `readonly` yazmak gürültü yaratıyordu.

8.2 ile sınıfın tamamını readonly ilan edebiliyorsunuz:

```php
readonly class Para
{
    public function __construct(
        public int $kurus,
        public string $birim = 'TRY',
    ) {}
}
```

Bu sınıfın bütün özellikleri otomatik olarak readonly olur. Bir `Para` nesnesi kurulduktan sonra değiştirilemez; değiştirmek isteyen yeni bir nesne üretir. Yıllardır [value object'leri](/blog/modern-phpde-deger-nesneleri-value-object-tasarlamak) elle "değiştirilemez" tutmaya çalışıyordum; artık bu garantiyi dil veriyor.

## readonly sınıfta bir kısıtlama

Readonly sınıfların bir sınırı var: bağımsız tipler dahil, tüm özellikler bir tipe sahip olmak zorunda. Tipsiz bir özelliğe readonly uygulanamıyor; readonly sınıfta da aynı kural geçerli. Dolayısıyla `public $alan` yazmak derleme hatası verecek; `public mixed $alan` yazmak gerekiyor.

Bu küçük bir kısıtlama gibi görünse de, yıllar önce tipsiz özelliklerle yazılmış value object'leri readonly sınıfa geçirirken gündeme gelebilir. Geçiş planlarken her özelliğin tipini kontrol etmek gerekiyor.

## DNF tipler

İkinci ekleme **ayrık normal form (Disjunctive Normal Form) tipleri**. Bugüne kadar `A&B` (kesişim) ve `A|B` (birleşim) tiplerini ayrı ayrı kullanabiliyorduk ama bir arada değil. 8.2 ile ikisini birleştirebiliyorsunuz:

```php
function kaydet((Countable&Iterator)|null $veri): void
```

Burada parametre ya `Countable` ve `Iterator` interface'lerinin ikisini birden karşılayan bir nesne ya da `null` olabilir. Günlük kodda sık gerekmez; ama kütüphane sınırlarında tip imzasını dürüst tutmayı sağlıyor.

Bunu en çok, nesne koleksiyonlarını işleyen yardımcı fonksiyonlarda kullanmak istediğimde karşıma çıkıyordu. "Hem gez hem say" diyebileceğim bir tip tanımlamak için `Traversable&Countable` yazmak istiyordum; 8.2 öncesinde bunu tip imzasına yazmanın temiz yolu yoktu.

## Tek başına `null`, `true`, `false`

Önceden `null` tek başına bir dönüş tipi olarak yazılamıyordu; bir `?something` içine gömmek gerekiyordu. 8.2 ile `null`, `true` ve `false` bağımsız tipler haline geliyor:

```php
function bul(int $id): User|null { /* ... */ }
function aktifMi(): true { /* ... */ }
```

Küçük bir düzeltme ama tip imzasının niyeti birebir anlatmasını sağlıyor.

## Dinamik özelliklerin kullanımdan kalkması

8.2 ayrıca tanımlanmamış bir özelliğe değer atamayı — yani dinamik özelliği — artık uyarıyla işaretliyor. Yıllar içinde `$nesne->yanlisYazilmisAlan = 1` satırı yüzünden saatlerce hata aradığım oldu. Bu davranışın kapanması, sınıfların ne tuttuğunu açıkça bildirmeye zorluyor; bu da iyi bir baskı.

Eski projelerde bu uyarılarla karşılaşmak kaçınılmaz olacak; bazı kod tabanlarında dinamik özellik atama kasıtlı kullanılmış olabilir. Bu geçiş için `#[AllowDynamicProperties]` özniteliği (attribute) geçici bir kaçış kapısı sunuyor. Ama kalıcı çözüm, özellikleri açıkça bildirmek.

## Neye yarıyor

Bu eklemelerin ortak teması şu: **dil, niyeti ifade etmek için daha fazla yer açıyor.** Readonly sınıf "bu nesne kurulduktan sonra sabittir" der; DNF tipler "bu parametre tam olarak şudur" der; dinamik özelliğin kapanması "bu sınıf yalnızca bunları tutar" der.

Bu tür eklemeler beni PHP'de yapı inşa etme biçimimi değiştiriyor. 8.1'deki enum ve readonly property'lerden sonra 8.2'deki readonly sınıf, dil ile niyet arasındaki boşluğu bir adım daha kapıyor. Sürüm çıkar çıkmaz value object'lerimi readonly sınıfa taşımayı planlıyorum. Büyük bir göç değil; ama kodun, daha önce yorum satırıyla ya da ekip disipliniyle koruduğum kuralları artık dilin kendisiyle anlatması hoşuma gidiyor. İyi bir sürüm, az kod yazdırarak çok şey garanti edendir.
