PHP 8.5'te clone() ile nesne özellikleri güncellemek için nesnenin bir kopyasını oluşturur, değiştirmek istediğin özellikleri ikinci parametre olarak verirsin. Böylece güncelleme yeni kopyada kalır; doğrudan özellik ataması ise aynı nesnenin durumunu değiştirir.
Başlıktaki clone() yazımı arama ifadesi olarak kullanılabilir, ancak gerçek kod biçimi clone($user, ['city' => 'Ankara']) şeklindedir. Klasik clone $user kullanımı kopya üretmeye devam eder; with anahtar sözcüğü ve clone $user with { city: 'Ankara' } biçimi PHP 8.5'te kullanılan sözdizimi değildir.
PHP 8.5'te clone ile özellik güncelleme: kısa cevap
PHP 8.5.0 ile clone, kopyalanan nesneye aktarılacak özellik değerlerini ikinci bir ilişkisel diziyle alan fonksiyon biçiminde kullanılabilir. PHP'nin klasik dil yapısı olan clone $user yalnızca kopya oluştururken, clone($user, ['city' => 'Ankara']) hem kopyayı oluşturur hem de belirtilen özelliği yeni nesne üzerinde günceller.
Bu özellik PHP duyurusunda ve ilgili RFC'de Clone With adıyla anılır. Buradaki kullanım, clone anahtar sözcüğünü koruyan ve ikinci parametre kabul eden fonksiyon benzeri biçimdir. Bu nedenle clone() için hem fonksiyon biçimi hem de clone dil yapısının yeni çağrı biçimi ifadelerini görebilirsin. PHP Clone With RFC'si bu tasarımın ayrıntılarını açıklar.
Sözdizimi şablonu: $copy = clone($object, ['property' => $value]);. İkinci parametrenin işlev imzası, array $withProperties = [] biçiminde bir özellik dizisidir. Dizide yalnızca belirtilen özellikler değiştirilir, diğer özellikler kopyalanan değerlerini korur.
PHP 8.5.0 öncesinde bu ikinci parametreli biçim bulunmuyordu; kopya oluşturma ile özellik değişikliğini tek çağrıda birleştirmek mümkün değildi. Bir __clone() metodu tanımlanmışsa önce o çalışır, ardından yeni değerler kopyaya uygulanır. readonly özellikler de kopya üzerinde güncellenebilir, ancak görünürlük ve tür kuralları geçerliliğini korur.
Nesne kopyalama ile doğrudan değişiklik arasındaki fark

PHP'de bir nesneyi başka bir değişkene atamak, yeni bir nesne üretmek anlamına gelmez. İki değişken aynı nesne örneğine erişir. Bu nedenle bir değişken üzerinden özellik atandığında, aynı nesneyi gören başka kod da güncellenmiş durumu okuyabilir.
Buradaki görünür durum değişikliği yan etki olarak düşünülebilir. Yan etki tek başına iyi veya kötü değildir. Paylaşılan bir durumu bilinçli olarak güncellemek istediğinde doğrudan mutasyon uygun olabilir; ancak bir metodun çağıran kodun elindeki nesneyi fark edilmeden değiştirmesi, akışı izlemeyi ve hatayı bulmayı zorlaştırabilir.
Kopya üretme yaklaşımı ise kaynak nesnenin durumunu koruyarak yeni nesne üzerinde çalışır. Kopya üretmek, mevcut nesnenin durumunu koruyarak yeni bir değer oluşturmayı sağlar. Bu yaklaşım, aynı başlangıç verisinden farklı sonuçlar üretmek veya bir metodun yeni nesne döndürmesini istemek gibi durumlarda daha açık bir sınır sunar. Karar verirken değişikliğin ortak nesnenin durumunu mu güncellemesi, yoksa mevcut değeri koruyan yeni bir sonuç mu üretmesi gerektiğine bakabilirsin.
User nesnesinde doğrudan değişiklik ve clone karşılaştırması
Doğrudan atama mevcut User nesnesini değiştirir. Klasik kopyalama clone $user biçimindedir. PHP 8.5'te seçili özelliği kopya oluşturulurken değiştiren biçim ise clone($user, ['city' => 'Bursa']) çağrısıdır.
<?php
class User
{
public string $city;
public function __construct(string $city)
{
$this->city = $city;
}
}
$user = new User('İzmir');
echo "Başlangıç değeri: {$user->city}n";
$user->city = 'Ankara';
echo "Doğrudan değişiklik sonrası: {$user->city}n";
$copy = clone($user, ['city' => 'Bursa']);
echo "Kopyanın şehri: {$copy->city}n";
echo "Clone işleminden sonra orijinalin şehri: {$user->city}n";
Beklenen çıktı:
Başlangıç değeri: İzmir
Doğrudan değişiklik sonrası: Ankara
Kopyanın şehri: Bursa
Clone işleminden sonra orijinalin şehri: Ankara
$user->city = 'Ankara' aynı nesnenin durumunu doğrudan değiştirir. Bu nesneye daha sonra erişen kod Ankara değerini görür; yeni bir nesne oluşmaz.
clone() ise ayrı bir kopya üretir ve Bursa değerini yalnızca kopyaya yazar. Bu nedenle orijinal nesne Ankara olarak kalır. User sınıfında __clone() bulunmadığından kopyalama sırasında ek işlem çalışmaz.
readonly sınıf ve özelliklerde izinler ve hatalar

readonly özellikler PHP 8.1'de, readonly sınıflar PHP 8.2'de, __clone() içindeki yeniden başlatma PHP 8.3'te, özellik güncelleyen clone() kullanımı ise PHP 8.5.0'da kullanılabilir. Ayrıntıları PHP'nin nesne kopyalama dokümantasyonunda bulabilirsin.
readonly özelliklerde izinler
Başlatılmış bir readonly özelliğe normal atama Error üretir. Klasik clone $nesne değeri kopyalar, fakat kopyadan sonra yapılan normal atama yine yasaktır. PHP 8.3'ten beri __clone(), sınıf kapsamından kopyadaki readonly özelliği yeniden başlatabilir. PHP 8.5'te özellik güncellemeleri __clone() sonrasında uygulanır ve yazma görünürlüğü denetlenmeye devam eder.
PHP 8.4'ten itibaren public readonly özellik dışarıdan okunabilir olsa da varsayılan yazma kapsamı protected(set)'tir. Dışarıdan güncelleme gerekiyorsa public(set) readonly açıkça belirtilmelidir.
| Durum | İşlem | Beklenen sonuç | Gerekçe |
|---|---|---|---|
| Başlatılmış readonly özellik | $obj->city = 'Ankara' |
Error |
Normal atama, başlatılmış değeri değiştiremez. |
| Klasik clone | $copy = clone $obj |
__clone() yoksa değer korunur. |
__clone() varsa kopyadaki özellik sınıf kapsamından yeniden başlatılabilir. |
| PHP 8.5 özellik güncellemesi | clone($obj, ['city' => 'Bursa']) |
Kapsam uygunsa kopyada Bursa, orijinalde eski değer kalır. | __clone() sonrası uygulanır, görünürlük kuralları geçerlidir. |
| readonly class | clone($this, ['city' => 'Bursa']) |
Metot içinden çalışır; dış kapsamda izin yoksa Error oluşur. |
Tanımlı özellikler readonly'dir ve dinamik özellik eklenemez. |
readonly class davranışı
readonly class, tanımlı özellikleri readonly yapar ve dinamik özellik oluşturulmasını engeller. Bu nedenle sınıf içindeki bir metot clone($this, ...) kullanabilir; aynı çağrı sınıf dışından yapıldığında yazma kapsamı yoksa hata verir.
<?php
readonly class Profile
{
public function __construct(public string $city)
{
}
public function withCity(string $city): self
{
return clone($this, ['city' => $city]);
}
}
$profile = new Profile('İzmir');
$updated = $profile->withCity('Bursa');
echo $updated->city; // Bursa
// Sınıf dışından yapılan ayrı deneme:
clone($profile, ['city' => 'Bursa']); // Error
İlk kullanım kopyada Bursa değerini üretir. Son satır sınıf dışından çalıştırıldığında yazma izni bulunmadığı için Error verir. Var olmayan bir özellik anahtarı kullanılırsa readonly sınıf içinde dinamik özellik oluşturulamayacağı için işlem yine hata ile sonuçlanır.
Doğrudan mutasyon mu, kopya üretimi mi?
Tek bir doğru yoktur. Aynı akışın yönettiği User nesnesinin yaşam döngüsü içinde kalacak bir değişiklik doğrudan mutasyonla okunabilir kalabilir. Eski durumu koruyarak yeni bir değer üretmek istediğinde PHP 8.5'teki clone($user, ['name' => 'Ece']) biçimi, yalnızca seçilen özelliği yeni kopyada günceller; diğer özellikler kopyalanan değerlerini korur.
- Değişiklik mevcut nesnenin yaşam döngüsünün parçası mı? Aynı akış nesneyi yönetiyor ve değişiklik normal ilerleyişin bir parçasıysa doğrudan güncelleme anlaşılır kalabilir.
- Önceki durum başka kod tarafından korunmalı mı? Başka kodun eski değeri kullanması gerekiyorsa kopya üretmek iki durumu ayırmayı kolaylaştırır.
- Sonraki satırlarda hangi değer okunacak? Değişkenin yeni değeri taşıdığı açık mı, yoksa eski ve yeni durumun ayrı tutulması mı gerekiyor?
- İç içe nesne veya referans kopyalama kuralı var mı? Kopyalanacak alanların paylaşılacağı veya ayrıca kopyalanacağı önceden belirlenmelidir.
readonlyve test edilebilirlik koşulları kararı etkiliyor mu? Yazma kısıtları ya da eski ve yeni durumları ayrı sınama ihtiyacı yöntemi değiştirebilir.
Örneğin, tek akışta kullanıcı durumunu güncelleyip sonraki adımlarda yalnızca yeni değeri okuyacaksan doğrudan değişiklik sade kalabilir. Eski durumu günlükleme, karşılaştırma veya geri alma için saklayacaksan kopya, iki durumu ayırmayı kolaylaştırabilir. Yeni nesnenin nasıl üretileceği ve __clone() içinde hangi alanların ayrıca kopyalanacağı da tasarımın parçasıdır.
İç içe nesnelerde clone sınırı
User içinde profile gibi başka bir nesne varsa, üst nesneyi klonlamak iç nesneyi otomatik olarak bağımsızlaştırmaz. Varsayılan kopyalama sığdır; __clone() içinde iç nesneyi ayrıca klonlamadığın sürece iki kullanıcı aynı Profile nesnesine erişebilir.
<?php
class Profile
{
public function __construct(
public string $city,
) {
}
}
class User
{
public function __construct(
public string $name,
public Profile $profile,
) {
}
}
$original = new User('Ada', new Profile('İzmir'));
$copy = clone($original, ['name' => 'Ece']);
$copy->profile->city = 'Ankara';
echo $original->profile->city, PHP_EOL;
echo $copy->profile->city, PHP_EOL;
Beklenen çıktı: İlk satır orijinal kullanıcının, ikinci satır kopyanın şehir değeridir.
Ankara
Ankara
$copy->profile->city değişirken orijinal değerin de değişmesi, iki User nesnesinin aynı Profile nesnesine eriştiğini gösterir. Bağımsız iç durum gerekiyorsa User::__clone() içinde $this->profile = clone $this->profile; gibi açık bir kural yazabilir veya sınıfı yeni bir Profile oluşturacak şekilde tasarlayabilirsin.
Sık Sorulan Sorular
PHP 8.5'te clone() bir fonksiyon mu, yoksa dil sözdizimi mi?
clone, ayrılmış bir PHP dil yapısıdır, normal bir kullanıcı fonksiyonu değildir. PHP 8.5 ile bu yapının parantezli biçimi ve ikinci parametre olarak özellik dizisi geldi. Bu özellik Clone With adıyla anılır. Genel sözdizimi clone(object $object, array $withProperties = []): object, pratik kullanım ise clone($user, ['name' => 'Ece']) şeklindedir. Eski clone $user biçimi de geçerliliğini korur.
Doğrudan değişiklikten sonra clone ile oluşturulan User kopyasını güncellemek orijinal nesneyi etkiler mi?
Önce orijinal User üzerinde yapılan doğrudan değişiklik, klonlama anındaki başlangıç durumuna dâhil olur. Klonlama sonrasında kopyanın kendi name gibi doğrudan bir özelliğini güncellemek orijinali etkilemez. Ancak kopyanın içindeki Profile gibi paylaşılan bir nesne değiştirilirse orijinal de etkilenebilir.
readonly bir özellik veya readonly class clone ile güncellenebilir mi?
Evet, PHP 8.5'te kopyalama sırasında clone($object, ['property' => $value]) kullanılarak kopyadaki readonly özellik, erişim kuralları ve tür koşulları izin verdiği sürece güncellenebilir. Aynı yaklaşım readonly class içindeki bir yöntemden dönen yeni kopya için de kullanılabilir. Orijinal nesne değişmez; başlatılmış bir readonly özelliğe sıradan $copy->property = ... ataması yapılamaz.
İçinde başka bir nesne bulunan User clone edildiğinde iç nesne de bağımsız olarak kopyalanır mı?
Hayır, varsayılan clone işlemi üst nesnenin özelliklerini sığ biçimde kopyalar. User::$profile başka bir nesneyi taşıyorsa, Profile ayrıca klonlanmadıkça orijinal ve kopya aynı iç nesneyi paylaşabilir. Bağımsız iç durum için __clone() içinde açıkça clone $this->profile uygulanmalıdır.
Bu nedenle karar, eski durumun korunup korunmayacağı ve iç nesnelerin paylaşım kuralının ne olacağı netleştirildiğinde daha kolay verilir.