
PHP'de Nesne Yönelimli Programlama: Sınıf, Nesne ve Kapsülleme
Nesne yönelimli programlamanın amacı kod satırlarını sınıflara bölmek değil, veriyi o veriyle çalışan davranışın yanında tutmaktır. Bir dizi ile onu işleyen beş ayrı fonksiyon arasında bağ yoktur; dizinin biçimi değiştiğinde beş fonksiyonun da güncellenmesi gerekir ve hangilerinin kaldığı yalnızca deneme yoluyla anlaşılır. Sınıf, bu bağı açıkça kurar.
Bu bölümde sınıf tanımı, yapıcı metot, görünürlük düzeyleri, değişmez nesneler ve sihirli metotlar ele alınıyor. Sınıfın ne zaman gerekli olduğu, bileşim ile kalıtım arasındaki tercih gibi tasarım soruları serinin sonraki bölümünde işleniyor.
Sınıf, nesne ve yapıcı metot
Sınıf bir kalıptır; nesne ise o kalıptan üretilmiş somut örnektir. Özellikler nesnenin durumunu, metotlar davranışını taşır. PHP 8 ile gelen yapıcı metot kısayolu, özellik tanımı ile atamayı tek yerde birleştirir.
final class Urun
{
public function __construct(
public readonly string $ad,
public readonly int $fiyatKurus,
private int $stok = 0,
) {}
public function stokDus(int $adet): void
{
if ($adet > $this->stok) {
throw new DomainException('Yetersiz stok');
}
$this->stok -= $adet;
}
public function stoktaVar(): bool
{
return $this->stok > 0;
}
}
$urun = new Urun(ad: 'Kamp sandalyesi', fiyatKurus: 129900, stok: 12);
$urun->stokDus(2);Örnekte stok bilgisi dışarıya kapalıdır. Azaltma işlemi yalnızca sınıfın kendi metodundan yapılabildiği için, stoğun eksiye düşmesini engelleyen kural tek bir yerde durur. Aynı kural özellik dışarı açık olsaydı, stoğu değiştiren her çağrı noktasında tekrarlanmak zorunda kalırdı.
Görünürlük düzeyleri
Üç düzey vardır. public her yerden, protected sınıf ve alt sınıflarından, private yalnızca tanımlandığı sınıftan erişilebilir. Varsayılan tercih private olmalıdır; bir üyenin dışarı açılması, o üyenin sözleşmenin parçası haline gelmesi demektir.
final class Hesap
{
private array $hareketler = [];
public function ekle(int $kurus): void
{
$this->hareketler[] = $kurus;
}
public function bakiye(): int
{
return array_sum($this->hareketler);
}
}PHP 8.4 ile okuma ve yazma için ayrı görünürlük tanımlanabiliyor. Aşağıdaki özellik dışarıdan okunur, ancak yalnızca sınıfın içinden değiştirilebilir. Bu yapı, okuyucu metot yazma ihtiyacını ortadan kaldırır.
final class Kullanici
{
public function __construct(
public private(set) string $ad,
) {}
public function adDegistir(string $yeni): void
{
$this->ad = $yeni;
}
}
$k = new Kullanici('Ali');
echo $k->ad; // okunur
$k->ad = 'Veli'; // Error: Cannot modify private(set) propertyDeğişmez nesneler
readonly ile işaretlenen özellik yalnızca tanımlandığı sınıfın içinden bir kez atanabilir. Sonraki her yazma denemesi hata verir. Değişmezlik, bir nesnenin başka bir yerde beklenmedik biçimde değiştirilmesini engellediği için hata ayıklamayı belirgin biçimde kolaylaştırır.
final readonly class Adres // tüm özellikleri readonly olur
{
public function __construct(
public string $sehir,
public string $ilce,
public string $posta,
) {}
public function sehirDegistir(string $yeni): self
{
return new self($yeni, $this->ilce, $this->posta); // yeni nesne üretilir
}
}Değişmez nesnelerde güncelleme, yeni bir nesne döndürerek yapılır. Bu yaklaşım ilk bakışta maliyetli görünse de nesne oluşturmak ucuz bir işlemdir ve kazandırdığı öngörülebilirlik çoğu durumda maliyetin çok üzerindedir.
Kimlik taşımayan, yalnızca değeriyle anlamlı olan kavramlar için değer nesnesi kullanılır: para, tarih aralığı, e-posta adresi. Doğrulama yapıcı metotta bir kez yapıldığında, o tipteki her nesnenin geçerli olduğu garanti altına alınır.
final readonly class Eposta
{
public function __construct(public string $deger)
{
if (filter_var($deger, FILTER_VALIDATE_EMAIL) === false) {
throw new InvalidArgumentException('Geçersiz e-posta adresi');
}
}
}
function bildirimGonder(Eposta $adres): void
{
// buraya ulaşan her adres geçerlidir, ek denetim gerekmez
}Nesne kopyalama ve karşılaştırma
Nesneler değişkenlere kopyalanmaz, tanıtıcı olarak taşınır. İki değişken aynı nesneyi gösterebilir ve birinden yapılan değişiklik diğerinde de görünür. Gerçek bir kopya gerekiyorsa clone kullanılır.
$a = new Sepet();
$b = $a; // aynı nesne
$c = clone $a; // yüzeysel kopya
// içeride nesne tutan alanlar da kopyalanmalıdır
final class Sepet
{
private ArrayObject $satirlar;
public function __clone(): void
{
$this->satirlar = clone $this->satirlar; // derin kopya
}
}Karşılaştırmada == aynı sınıftan olup olmadıklarına ve özelliklerinin eşitliğine bakar, === ise tam olarak aynı nesne olup olmadıklarını sorgular. Değer nesnelerinde eşitlik genellikle == ile ya da sınıfa yazılan bir karşılaştırma metoduyla ifade edilir.
Sihirli metotlar
Belirli durumlarda PHP tarafından kendiliğinden çağrılan metotlar vardır. En yaygın kullanılanı, nesnenin metne çevrilmesini tanımlayan metottur.
final class Para
{
public function __construct(private readonly int $kurus) {}
public function __toString(): string
{
return number_format($this->kurus / 100, 2, ',', '.') . ' TL';
}
}
echo new Para(129900); // 1.299,00 TL__get ve __set ile tanımsız özelliklere erişim yakalanabilir. Bu iki metot kolaylık sağlıyor gibi görünse de sınıfın hangi özellikleri taşıdığını koddan gizler, düzenleyicilerin tamamlama yapmasını engeller ve yazım hatalarını çalışma zamanına erteler. PHP 8.4 ile gelen özellik kancaları, hesaplanan değerler için çok daha güvenli bir yol sunar.
final class Kisi
{
public function __construct(
private string $ad,
private string $soyad,
) {}
public string $tamAd {
get => $this->ad . ' ' . $this->soyad;
}
}
echo (new Kisi('Ayşe', 'Demir'))->tamAd; // Ayşe DemirNesne üretimini denetlemek
Yapıcı metodun aldığı parametreler her zaman elde hazır bulunmaz. Veritabanı satırından, form verisinden ya da API yanıtından nesne üretmek gerektiğinde dönüşümü çağrı noktasına bırakmak yerine adlandırılmış üretici metotlar kullanılır. Bu metotlar hem dönüşümü tek yerde toplar hem de adlarıyla niyeti anlatır.
final class Kayit
{
private function __construct(
public readonly int $id,
public readonly string $baslik,
public readonly DateTimeImmutable $olusturma,
) {}
public static function satirdan(array $satir): self
{
return new self(
id: (int) $satir['id'],
baslik: (string) $satir['baslik'],
olusturma: new DateTimeImmutable($satir['olusturma'], new DateTimeZone('UTC')),
);
}
public static function yeni(string $baslik, Saat $saat): self
{
return new self(0, $baslik, $saat->simdi());
}
}Yapıcı metodun kapatılması, nesnenin yalnızca tanımlı yollardan üretilmesini sağlar. Böylece eksik ya da tutarsız bir nesnenin var olması dilin kuralıyla engellenir; her üretim yolu kendi doğrulamasını yapar.
Sınıf ne zaman gereksizdir
Her işlemin sınıfa dönüştürülmesi gerekmez. Tek bir girdi alıp tek bir çıktı üreten, durum tutmayan bir işlem için fonksiyon yeterlidir. Yalnızca özellik taşıyıp davranış içermeyen sınıflar da çoğu zaman gereksizdir; bu durumda davranışın nereye kaçtığı sorulmalıdır.
- Sınıfta yalnızca alıcı ve atayıcı metotlar varsa, kurallar başka bir yerde tekrarlanıyor demektir.
- Bir metot yalnızca parametrelerini kullanıp nesnenin durumuna hiç dokunmuyorsa, o metot sınıfa ait olmayabilir.
- Adı yönetici, işleyici ya da yardımcı ile biten sınıflar genellikle birbirine ait olmayan işleri toplar.
Kontrol listesi
- Özellikler varsayılan olarak
private; dışarı açılan her üye bilinçli bir karar. - Yapıcı metot, nesneyi geçerli bir durumda üretiyor; eksik veriyle nesne oluşturulamıyor.
- Değişmeyen alanlar
readonlyile işaretli. - Doğrulama kuralları çağrı noktalarında değil, ilgili sınıfın içinde.
- Nesne kopyalamada iç nesneler için
__clonetanımlı. __getve__setyerine açık özellik ya da kanca kullanılıyor.
İlgili yazılar
- Sınıf ne zaman gerekir: soyutlama ve bağımlılık yönü
- Temiz kod: isimlendirme ve fonksiyon boyutu
- Tip bildirimleri ve katı mod
PHP eğitim serisi
Bu yazı, temel sözdiziminden üretim ortamına kadar ilerleyen 25 bölümlük serinin bir parçası. Bölümler sırayla okunacak biçimde hazırlandı, ancak her biri tek başına da kullanılabilir.
Temeller
- Kurulum ve temel sözdizimi
- Döngüler ve akış kontrolü
- Diziler
- Fonksiyonlar
- String fonksiyonları
- Süper globaller
- Form işleme
- Dosya işlemleri
Dilin ayrıntıları
Nesne yönelimli PHP
- Sınıf ve nesne (bu yazı)
- Kalıtım, arayüz ve trait
- Statik üyeler, sabitler ve enum
- Namespace, Composer ve autoload
Veri ve güvenlik
- PDO ile veritabanı işlemleri
- Oturum yönetimi ve kimlik doğrulama
- Güvenli çıktı ve XSS
- JSON ile veri değişimi
Dış dünya ve üretim
Yorumlar
İlk yorumu sen yap.
İlgili Yazılar

PHP Uygulamasını Üretime Almak: Yapılandırma ve Güvenlik
Geliştirme makinesinde çalışan kod ile üretimde güvenle çalışan kod arasındaki fark yapılandırmadır. Ayarlar, izinler, dağıtım akışı ve son kontroller.

PHP ile REST API Yazmak: Yönlendirme ve HTTP Durum Kodları
Bir API'nin kalitesi çoğunlukla ayrıntılarda belli olur: doğru durum kodu, tutarlı hata biçimi ve öngörülebilir adresler. Saf PHP ile uçtan uca kurulum.

PHPUnit ile Birim Test Yazmak: Kurulum, Sahte Nesneler ve Kapsam
Testin amacı hata bulmak değil, değişikliği güvenle yapabilmektir. Kurulum, ilk test, sahte nesneler ve test edilebilir kodun özellikleri.