PHP 8+ ile Encapsulation ve Private Properties
PHP 8+ ile birlikte gelen modern özelliklerle encapsulation (kapsülleme) prensibini derinlemesine inceleyelim.
Temel Kavram: Neden Private?
Verileri gizleyip davranışı ortaya çıkarmanın amacı:
- Değişimin kontrolü: Dışarıdan doğrudan erişimi engelleyerek değişiklikleri kontrol edersiniz
- İç implementasyon özgürlüğü: İç yapıyı değiştirdiğinizde dış kodlar etkilenmez
- Veri tutarlılığı: Validation ve business logic'i merkezi bir noktada yönetirsiniz
PHP 8.0+ Constructor Property Promotion
PHP 8.0'ın getirdiği en önemli özelliklerden biri:
<?php // ❌ Eski yöntem (PHP 7.x) class User { private string $name; private string $email; private int $age; public function __construct(string $name, string $email, int $age) { $this->name = $name; $this->email = $email; $this->age = $age; } } // ✅ Yeni yöntem (PHP 8.0+) class User { public function __construct( private string $name, private string $email, private int $age ) {} // Getter'lar ile davranış ortaya çıkarma public function getName(): string { return $this->name; } public function getEmail(): string { return $this->email; } public function getAge(): int { return $this->age; } // Kontrollü değişim public function updateEmail(string $newEmail): void { if (!filter_var($newEmail, FILTER_VALIDATE_EMAIL)) { throw new InvalidArgumentException('Geçersiz email formatı'); } $this->email = $newEmail; } public function celebrateBirthday(): void { $this->age++; } }
PHP 8.1+ Readonly Properties
PHP 8.1 ile gelen readonly özelliği immutability sağlar:
<?php class Product { public function __construct( private readonly string $id, private readonly string $name, private float $price, private readonly DateTime $createdAt ) {} // ID ve name değiştirilemez (readonly) public function getId(): string { return $this->id; } public function getName(): string { return $this->name; } // Fiyat değiştirilebilir ama kontrollü public function getPrice(): float { return $this->price; } public function applyDiscount(float $percentage): void { if ($percentage < 0 || $percentage > 100) { throw new InvalidArgumentException('İndirim 0-100 arasında olmalı'); } $this->price = $this->price * (1 - $percentage / 100); } public function getCreatedAt(): DateTime { // ⚠️ DateTime mutable bir object, clone ile koruma return clone $this->createdAt; } } $product = new Product('P001', 'Laptop', 15000.0, new DateTime()); echo $product->getPrice(); // 15000 $product->applyDiscount(20); // %20 indirim echo $product->getPrice(); // 12000 // $product->id = 'P002'; // ❌ HATA: Readonly property
PHP 8.2+ Readonly Classes
Tüm class'ı immutable yapmak için:
<?php readonly class Money { public function __construct( public float $amount, public string $currency ) {} // Yeni bir Money objesi döndürerek değişimi yönetme public function add(Money $other): self { if ($this->currency !== $other->currency) { throw new InvalidArgumentException('Para birimleri eşleşmiyor'); } return new self( $this->amount + $other->amount, $this->currency ); } public function multiply(float $factor): self { return new self( $this->amount * $factor, $this->currency ); } public function format(): string { return number_format($this->amount, 2) . ' ' . $this->currency; } } $price = new Money(100, 'TRY'); $tax = new Money(18, 'TRY'); $total = $price->add($tax); echo $total->format(); // 118.00 TRY // $price->amount = 200; // ❌ HATA: Readonly property
Pratik Örnek: E-Ticaret Sepet Sistemi
<?php readonly class CartItem { public function __construct( public string $productId, public string $productName, public float $unitPrice, public int $quantity ) { if ($quantity <= 0) { throw new InvalidArgumentException('Miktar pozitif olmalı'); } } public function getTotalPrice(): float { return $this->unitPrice * $this->quantity; } public function changeQuantity(int $newQuantity): self { return new self( $this->productId, $this->productName, $this->unitPrice, $newQuantity ); } } class ShoppingCart { /** @var array<string, CartItem> */ private array $items = []; public function addItem(CartItem $item): void { $productId = $item->productId; if (isset($this->items[$productId])) { $existingItem = $this->items[$productId]; $newQuantity = $existingItem->quantity + $item->quantity; $this->items[$productId] = $existingItem->changeQuantity($newQuantity); } else { $this->items[$productId] = $item; } } public function removeItem(string $productId): void { unset($this->items[$productId]); } public function updateQuantity(string $productId, int $quantity): void { if (!isset($this->items[$productId])) { throw new InvalidArgumentException('Ürün sepette bulunamadı'); } if ($quantity <= 0) { $this->removeItem($productId); } else { $this->items[$productId] = $this->items[$productId] ->changeQuantity($quantity); } } /** @return array<CartItem> */ public function getItems(): array { return array_values($this->items); } public function getTotalAmount(): float { return array_reduce( $this->items, fn($total, $item) => $total + $item->getTotalPrice(), 0.0 ); } public function getItemCount(): int { return array_reduce( $this->items, fn($total, $item) => $total + $item->quantity, 0 ); } public function clear(): void { $this->items = []; } } // Kullanım $cart = new ShoppingCart(); $laptop = new CartItem('P001', 'Laptop', 15000, 1); $mouse = new CartItem('P002', 'Mouse', 250, 2); $cart->addItem($laptop); $cart->addItem($mouse); echo "Toplam ürün: " . $cart->getItemCount() . "\n"; // 3 echo "Toplam tutar: " . $cart->getTotalAmount() . " TRY\n"; // 15500 TRY $cart->updateQuantity('P002', 5); echo "Güncel tutar: " . $cart->getTotalAmount() . " TRY\n"; // 16250 TRY // ❌ Dışarıdan doğrudan erişim yok // $cart->items['P001']->quantity = 10; // Private property
Özet
PHP 8+ ile encapsulation'ı uygulamak için:
- Constructor Property Promotion kullanın (PHP 8.0+)
- Readonly properties ile immutability sağlayın (PHP 8.1+)
- Readonly classes ile tam immutable objeler oluşturun (PHP 8.2+)
- Getter/Setter yerine davranışı ortaya çıkaran metodlar yazın
- Validation logic'i her zaman içeride tutun
- Return type declarations ile tip güvenliği sağlayın
Bu yaklaşım sayesinde kodunuz daha güvenli, test edilebilir ve sürdürülebilir olur!
PHP 8+ ile "tüm özellikleri private yapmak" şu anlama gelir:
-
Varsayılan: Veriyi
privateyap, davranışıpublicmetotla aç. -
Daha Kolay:
privateözellikleriConstructor Property Promotionile hızlıca tanımla. -
Daha Güvenli (Durum):
stringveyaintgibi ilkel tipler yerineprivate Enumkullanarak iş kurallarını tipe dönüştür. -
En Güvenli (Değişmezlik): Asla değişmemesi gereken veriler için
private readonlykullanarak nesnenin temelini kilitle.

0 Comments
Recommended Comments
There are no comments to display.