Nesne Klonlama: Derinlemesine İnceleme
Coddy'nin PHP Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 61 / 91.
Bu kursun başlarında __clone sihirli metodu hakkında bilgi edindiniz. Şimdi, nesneler özellik olarak başka nesneler içerdiğinde yüzeysel (shallow) ve derin (deep) kopyalama arasındaki kritik farkı inceleyelim.
Varsayılan olarak PHP, kopyalama işlemi sırasında sığ bir kopyalama (shallow copy) gerçekleştirir. Skaler değerler çoğaltılır, ancak nesne özellikleri aynı nesnelere referans olarak kalmaya devam eder:
<?php
class Address {
public function __construct(public string $city) {}
}
class Person {
public function __construct(
public string $name,
public Address $address
) {}
}
$original = new Person("Alice", new Address("Paris"));
$clone = clone $original;
$clone->name = "Bob";
$clone->address->city = "London";
echo $original->name . " - " . $original->address->city;
Çıktı:
Alice - London$clone->name değerini değiştirmenin orijinali etkilemediğini, ancak adres şehrini değiştirmenin etkilediğini fark edin! Her iki nesne de aynı Address örneğini paylaşıyor.
İç içe geçmiş nesnelerin de kopyalandığı bir derin kopya oluşturmak için __clone metodunu uygulayın:
<?php
class Person {
public function __construct(
public string $name,
public Address $address
) {}
public function __clone(): void {
$this->address = clone $this->address;
}
}
$original = new Person("Alice", new Address("Paris"));
$clone = clone $original;
$clone->address->city = "London";
echo $original->address->city;
Çıktı:
ParisArtık her Person kendi bağımsız Address nesnesine sahip. Nesneleriniz birden fazla iç içe geçmiş nesne içerdiğinde, orijinal ile kopya arasında gerçek bağımsızlık sağlamak için __clone içinde her birini kopyalamanız gerekir.
Görev
KolayYüzeysel (shallow) ve derin (deep) kopyalama arasındaki farkı gösteren bir belge yönetim sistemi oluşturalım. Yazar bilgilerini içeren belgeler oluşturacak ve bir belgeyi kopyalamanın gerçekten bağımsız bir kopya oluşturmasını sağlayacaksınız.
Kodunuzu üç dosya halinde düzenleyeceksiniz:
Author.php— Bir belgenin yazarını temsil eden birAuthorsınıfı oluşturun. Genel bir$name(string) ve genel bir$email(string) tanımlamak için constructor promotion kullanın.Document.php— Bir yazar içeren birDocumentsınıfı oluşturun. Author dosyasını dahil edin. Sınıf şunları yapmalıdır:- Genel bir
$title(string) ve genel bir$author(Author) için constructor promotion kullanın - Derin kopyalama gerçekleştirmek için
__clone()sihirli metodunu uygulayın — bir belge kopyalandığında, kopyanın yazarında yapılan değişikliklerin orijinali etkilememesi için yazarı da kopyalanmalıdır "[title] by [author name] ([author email])"döndüren birgetInfo()metoduna sahip olun
- Genel bir
main.php— Document dosyasını dahil edin. Üç girdi alacaksınız: bir belge başlığı, bir yazar adı ve bir yazar e-postası.Sağlanan girdileri kullanarak bir
Authorile birDocumentoluşturun. Belgeyi kopyalayın, ardından kopyanın yazar adına" (Copy)"ekleyerek ve kopyanın başlığının başına"Copy of "ekleyerek kopyayı değiştirin.İki satır yazdırın:
- Orijinal belgenin bilgileri
- Kopyalanan belgenin bilgileri
Derin kopyalamanız doğru şekilde uygulandıysa, kopyanın yazarı değiştirildikten sonra bile orijinal belgenin yazarı değişmeden kalmalıdır.
Bu meydan okuma, derin kopyalamanın neden önemli olduğunu gösterir — __clone() metodunun uygun şekilde uygulanması olmadan, her iki belge de aynı Author nesnesini paylaşır ve birini değiştirmek diğerini de etkiler.
Kopya kağıdı
Varsayılan olarak PHP, nesneleri kopyalarken bir yüzeysel kopyalama (shallow copy) gerçekleştirir. Skaler değerler çoğaltılır, ancak nesne özellikleri aynı nesnelere referans olarak kalmaya devam eder.
Yüzeysel kopyalama örneği:
<?php
class Address {
public function __construct(public string $city) {}
}
class Person {
public function __construct(
public string $name,
public Address $address
) {}
}
$original = new Person("Alice", new Address("Paris"));
$clone = clone $original;
$clone->name = "Bob";
$clone->address->city = "London";
echo $original->name . " - " . $original->address->city;
// Çıktı: Alice - London
$clone->name değerini değiştirmek orijinali etkilemez, ancak iç içe geçmiş address nesnesini değiştirmek etkiler; çünkü her iki nesne de aynı Address örneğini paylaşır.
İç içe geçmiş nesnelerin de kopyalandığı bir derin kopyalama (deep copy) oluşturmak için __clone sihirli metodunu uygulayın:
<?php
class Person {
public function __construct(
public string $name,
public Address $address
) {}
public function __clone(): void {
$this->address = clone $this->address;
}
}
$original = new Person("Alice", new Address("Paris"));
$clone = clone $original;
$clone->address->city = "London";
echo $original->address->city;
// Çıktı: Paris
Nesneler birden fazla iç içe geçmiş nesne içerdiğinde, orijinal ile kopya arasında gerçek bir bağımsızlık sağlamak için __clone içinde her birini kopyalamanız gerekir.
Kendin dene
<?php
require_once 'Document.php';
// Girdileri oku
$title = trim(fgets(STDIN));
$authorName = trim(fgets(STDIN));
$authorEmail = trim(fgets(STDIN));
// TODO: Sağlanan isim ve e-posta ile bir Yazar (Author) oluşturun
// TODO: Sağlanan başlık ve Yazar ile bir Belge (Document) oluşturun
// TODO: Belgeyi kopyalayın (clone)
// TODO: Kopya belgenin yazar isminin sonuna " (Copy)" ekleyerek değiştirin
// TODO: Kopya belgenin başlığının başına "Copy of " ekleyerek değiştirin
// TODO: Orijinal belgenin bilgilerini yazdırın
// TODO: Kopyalanan belgenin bilgilerini yazdırın
?>Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Nesne Yönelimli Programlama bölümündeki tüm dersler
1OOP Temelleri
Harici DosyalarOOP'ye GirişSınıflar ve Nesneler$this Anahtar KelimesiMetotlarÖzelliklerYapıcı Metot (__construct)Yıkıcı Metot (__destruct)Özet - Basit Hesap Makinesi4Kalıtım
Temel Kalıtımparent:: Anahtar KelimesiMetot Geçersiz Kılmafinal Anahtar KelimesiSoyut SınıflarÖzet - Çalışan Hiyerarşisi7Kapsülleme
Public, Protected, PrivateErişim Belirleyicilere Derinlemesine BakışGetter ve Setter MetotlarıBilgi GizlemeConstructor Promotion (8.0)Özet - Öğrenci Kayıt Sistemi10İleri Düzey OOP Kavramları
Kompozisyon vs KalıtımDependency InjectionAnonim SınıflarEnum'lar (PHP 8.1)Fiber'lar (PHP 8.1)Nesne Klonlama: Derinlemesine İncelemeGenerator'lar ve Iterator'lar13Tasarım Kalıpları Bölüm 2
Komut KalıbıAdaptör KalıbıDekoratör KalıbıŞablon Metot KalıbıDurum KalıbıKompozit KalıbıRepository Kalıbı2İsim Alanları ve Autoloading
İsim Alanlarına Girişuse Anahtar KelimesiPSR-4 Autoloading StandartıComposer AutoloaderÖzet - Düzenli Proje5Arayüzler ve Sözleşmeler
Arayüzlere GirişArayüzleri UygulamaBirden Fazla Arayüz UygulamaArayüz vs Soyut SınıfArayüzler ile Tip BelirlemeÖzet - Şekil Hesaplayıcı8Sihirli Metotlar
Sihirli Metotlara Giriş__toString & __debugInfo__get, __set, __isset, __unset__call & __callStatic__clone & Nesne Klonlama__serialize & __unserializeÖzet - Özel Koleksiyon3Sınıf Özellikleri
Örnek ve Statik ÖzelliklerSınıflarda SabitlerStatik Metotlar ve ÖzelliklerPrivate ve Protected ÖzelliklerReadonly Özellikler (PHP 8.1)Özet - Banka Hesabı Yöneticisi6Çok Biçimlilik
Metot Geçersiz Kılmaya Yeniden BakışArayüzler ile Çok BiçimlilikType Hinting ve Union TypesLate Static BindingÖzet - Ödeme İşlemcisi9Trait'ler
Trait'lere GirişÇoklu Trait KullanımıTrait Çakışma ÇözümüTrait'lerde Soyut MetotlarTrait'ler ve Kalıtım12Tasarım Kalıpları Bölüm 1
Tasarım Kalıplarına GirişSingleton KalıbıFactory KalıbıObserver KalıbıStrategy Kalıbı15Final Meydan Okumaları
E-Öğrenme PlatformuBankacılık SistemiOyun Karakteri GeliştirmeAraç Kiralama Servisi