PHP'de dizi (array), değerleri anahtarlarla eşleştiren sıralı bir haritadır. Aynı yapı hem 0'dan başlayan numaralı bir liste, hem metin anahtarlı bir sözlük, hem de iç içe veri ağacı olarak kullanılabilir. Dizi oluşturmak için [] ya da array() yazarsınız; anahtar yalnızca int veya string olabilir, değer ise her tipten olabilir.

Bu yazıda dizilerin nasıl oluşturulduğunu, anahtarların hangi kurallarla dönüştürüldüğünü, eleman ekleme ve silmenin arka planda nasıl işlediğini, destructuring (dizi açma) ve spread (...) sözdizimini, + ile array_merge() arasındaki farkı ve en sık yapılan hataları anlatıyoruz. Dizi fonksiyonlarını array_map, array_filter ve diğer dizi fonksiyonları yazısında, sıralamayı ise PHP dizi sıralama yazısında ayrıca ele aldık.

PHP dizisi neden "sıralı harita"dır?

Birçok dilde dizi ve sözlük ayrı tiplerdir: JavaScript'te Array ile Map, Python'da list ile dict gibi. PHP ise bu ayrımı yapmaz. Kılavuzun tanımına göre dizi, değerleri anahtarlara bağlayan ve eklenme sırasını koruyan tek bir tiptir. Numaralı (indexed) dizi dediğimiz şey aslında anahtarları 0, 1, 2 diye giden bir haritadır; ilişkisel (associative) dizi ise anahtarları metin olan bir haritadır. İkisi aynı dizide karışık olarak da bulunabilir.

Bu tasarımın pratik bir sonucu var: dizinin elemanları anahtar sırasına göre değil, eklendikleri sıraya göre dolaşılır. [5 => 'a', 1 => 'b'] dizisini foreach ile gezdiğinizde önce 'a' gelir. Ayrıca bir dizinin "liste" olup olmadığı, yani anahtarlarının 0'dan başlayıp boşluksuz artıp artmadığı ayrı bir sorudur ve bunun için PHP 8.1'den beri array_is_list() fonksiyonu vardır.

Dizi oluşturma: [] ve array()

Kısa sözdizimi [] ile uzun sözdizimi array() tamamen aynı sonucu verir. Anahtar belirtmek için anahtar => değer çiftleri yazarsınız; anahtarı atlarsanız PHP otomatik bir tam sayı anahtar verir. Son elemandan sonraki virgül isteğe bağlıdır. Çok satırlı dizilerde sondaki virgülü bırakmak, yeni satır eklerken önceki satırı değiştirme gereğini ortadan kaldırdığı için yaygın bir alışkanlıktır.

php
<?php
$renkler = ['kırmızı', 'yeşil', 'mavi'];          // numaralı dizi
$kullanici = [
    'ad'    => 'Ayşe',
    'sehir' => 'İzmir',
    'yas'   => 31,
];                                                 // ilişkisel dizi
$eski = array('kırmızı', 'yeşil', 'mavi');         // aynı dizi, uzun sözdizimi

var_dump($renkler === $eski);   // çıktı: bool(true)
echo $renkler[1], "\n";         // çıktı: yeşil
echo $kullanici['sehir'], "\n"; // çıktı: İzmir
echo count($kullanici), "\n";   // çıktı: 3

Anahtar kuralları ve otomatik dönüşümler

Anahtar kuralları ve otomatik dönüşümler: Geçerli bir ondalık tam sayı içeren metin, tam sayıya çevrilir: '8' anahtarı 8..., float anahtarın ondalık kısmı atılır, bool anahtar tam...

Anahtar olarak yalnızca int ve string saklanır. Başka bir tip verdiğinizde PHP onu sessizce dönüştürür ve bu dönüşümler, birbirinin üzerine yazan anahtarlar yüzünden şaşırtıcı sonuçlar doğurabilir. Kılavuzda sayılan kurallar şunlardır:

  • Geçerli bir ondalık tam sayı içeren metin, tam sayıya çevrilir: '8' anahtarı 8 olarak saklanır. Ancak '08' geçerli bir ondalık tam sayı yazımı olmadığı için metin olarak kalır. Başında + işareti olan '+3' da metin olarak kalır; '-5' ise tam sayı -5 olur.
  • float anahtarın ondalık kısmı atılır: 8.7 anahtarı 8 olur. PHP 8.1'den beri bu kayıplı dönüşüm bir Deprecated uyarısı da üretir.
  • bool anahtar tam sayıya döner: true değeri 1, false değeri 0 olur.
  • null anahtar boş metne ('') dönüşür. PHP 8.5 ile null'ı dizi anahtarı olarak kullanmak kullanımdan kaldırılacaklar (deprecated) listesine girdi; bunun yerine açıkça '' yazmanız öneriliyor.
  • Dizi ve nesne anahtar olamaz; denerseniz hata alırsınız.

Aynı anahtara dönüşen birden fazla eleman yazarsanız yalnızca sonuncusu kalır. Aşağıdaki örnekte 1, '1' ve true aynı anahtara düştüğü için üç eleman tek elemana iner:

php
<?php
$dizi = [
    1    => 'a',
    '1'  => 'b',   // 1 anahtarına düşer, 'a' silinir
    '08' => 'c',   // metin olarak kalır
    true => 'd',   // yine 1 anahtarı, 'b' silinir
    '-5' => 'e',   // tam sayı -5 olur
    '+3' => 'f',   // + işaretli olduğu için metin kalır
];
var_dump($dizi);
/* çıktı:
array(4) {
  [1]=>
  string(1) "d"
  ["08"]=>
  string(1) "c"
  [-5]=>
  string(1) "e"
  ["+3"]=>
  string(1) "f"
}
*/

Ondalık sayıyla anahtar vermek hem bilgi kaybına yol açar hem de uyarı üretir. Bu durum özellikle fiyat veya ölçüm değerlerini anahtar olarak kullanmaya çalışırken ortaya çıkar:

php
<?php
$fiyatlar = [];
$fiyatlar[2.7] = 'iki virgül yedi';
var_dump($fiyatlar);
/* çıktı:
Deprecated: Implicit conversion from float 2.7 to int loses precision in /yol/ornek.php on line 3
array(1) {
  [2]=>
  string(16) "iki virgül yedi"
}
*/

Anahtarsız ekleme: PHP hangi numarayı verir?

$dizi[] = değer yazdığınızda ya da dizi tanımında anahtarı atladığınızda PHP, o ana kadar kullanılmış en büyük tam sayı anahtarın bir fazlasını verir. Burada önemli bir ayrıntı var: o en büyük anahtarın şu anda dizide bulunması gerekmez. Bir elemanı unset() ile silseniz bile PHP sayacı geri almaz. Numaraları sıfırdan yeniden dizmek istiyorsanız array_values() kullanırsınız.

php
<?php
$meyve = ['elma', 'armut', 10 => 'kiraz', 'erik'];
echo implode(', ', array_keys($meyve)), "\n";  // çıktı: 0, 1, 10, 11

unset($meyve[11]);
$meyve[] = 'incir';
echo implode(', ', array_keys($meyve)), "\n";  // çıktı: 0, 1, 10, 12

$meyve = array_values($meyve);
echo implode(', ', array_keys($meyve)), "\n";  // çıktı: 0, 1, 2, 3

$negatif = [];
$negatif[-5] = 'x';
$negatif[] = 'y';
echo implode(', ', array_keys($negatif)), "\n"; // çıktı: -5, -4

Son satırdaki davranış PHP 8.3'te değişti. Kılavuza göre 8.3'ten önce, tek anahtarı negatif olan bir diziye anahtarsız eleman eklendiğinde yeni anahtar 0 olurdu; artık negatif anahtarın bir fazlası, yani -4 verilir. Eski bir kod tabanını taşıyorsanız negatif anahtarlarla çalışan yerleri kontrol etmeniz iyi olur.

Elemanlara erişim ve olmayan anahtarlar

Elemanlara erişim ve olmayan anahtarlar

Elemana köşeli parantezle erişirsiniz: $dizi['anahtar'] veya $dizi[0]. İç içe dizilerde parantezleri arka arkaya yazarsınız. Fonksiyonun döndürdüğü diziye de doğrudan erişebilirsiniz: getir()[1]. PHP 8.0'dan önce süslü parantezli $dizi{0} yazımı da çalışıyordu; artık desteklenmiyor.

Var olmayan bir anahtarı okumak, tanımsız değişken okumak gibi davranır: PHP 8'de E_WARNING seviyesinde Undefined array key uyarısı verilir ve sonuç null olur. Program durmaz ama uyarı, hatalı veriyle devam ettiğinizin işaretidir. Anahtarın olmayabileceğini biliyorsanız null birleştirme operatörü ?? ile varsayılan değer verin. Bu uyarıyı ve isset() ile array_key_exists() farkını Undefined array key uyarısı yazısında ayrıntılı anlattık.

php
<?php
$kullanici = ['ad' => 'Ayşe', 'sehir' => 'İzmir'];

echo $kullanici['ad'], "\n";                    // çıktı: Ayşe
echo $kullanici['yas'] ?? 'bilinmiyor', "\n";   // çıktı: bilinmiyor
echo $kullanici['yas'];
// çıktı: Warning: Undefined array key "yas" in /yol/ornek.php on line 6

Eleman ekleme, değiştirme ve silme

Var olan bir anahtara atama yaparsanız değer değişir, olmayan bir anahtara atama yaparsanız yeni eleman eklenir. Elemanı silmek için unset($dizi['anahtar']) kullanılır. unset() diziyi yeniden numaralamaz; ortada bir boşluk kalır. Bu boşluk çoğu zaman sorun değildir, ama diziyi JSON'a çevirdiğinizde veya for döngüsüyle 0'dan count() - 1'e kadar dolaştığınızda fark edilir.

Kılavuz, değişkeni önceden tanımlamadan $dizi[] = ... ile dizi oluşturmayı önermez. Değişken daha önce bir metin taşıyorsa köşeli parantez metin üzerinde çalışmaya kalkar; PHP 7.1'den beri boş indeksli atama metinde ölümcül hata verir. PHP 8.1'den beri false değerinden otomatik dizi oluşturmak da kullanımdan kaldırılmıştır. En güvenli yol, değişkeni her zaman $dizi = []; ile başlatmaktır.

Dizi ataması değer kopyalar

PHP'de bir diziyi başka bir değişkene atamak, onun bir kopyasını oluşturur. Kopyada yaptığınız değişiklik asıl diziyi etkilemez. Bu, nesnelerin davranışından farklıdır: nesne değişkenleri aynı nesneyi gösterir. Diziyi fonksiyona parametre olarak geçirdiğinizde de fonksiyon kendi kopyasıyla çalışır. İki değişkenin aynı diziyi paylaşmasını istiyorsanız referans operatörü & gerekir; referansların inceliklerini PHP referanslar yazısında bulabilirsiniz.

php
<?php
$a = [1, 2, 3];
$b = $a;          // kopya
$b[] = 4;
echo count($a), ' ', count($b), "\n"; // çıktı: 3 4

$c = &$a;         // referans: $c ve $a aynı dizi
$c[] = 99;
echo count($a), "\n";                 // çıktı: 4

Çok boyutlu diziler

Değer her tipten olabildiği için bir dizinin elemanı başka bir dizi olabilir. Veritabanından gelen satırlar, yapılandırma verisi veya sipariş listeleri genellikle bu şekilde tutulur. İç içe bir anahtara atama yaptığınızda aradaki diziler yoksa PHP onları kendisi oluşturur. count() fonksiyonuna COUNT_RECURSIVE verirseniz alt dizilerin elemanları da sayılır; bu sayıma alt dizilerin kendisi de dahildir, bu yüzden sonuç ilk bakışta beklenenden büyük çıkar.

php
<?php
$siparisler = [
    'S-1001' => ['musteri' => 'Ali',    'urunler' => ['kalem', 'defter']],
    'S-1002' => ['musteri' => 'Zeynep', 'urunler' => ['silgi']],
];
echo $siparisler['S-1001']['urunler'][1], "\n";   // çıktı: defter

$siparisler['S-1003']['musteri'] = 'Can';          // ara dizi kendiliğinden oluşur
$siparisler['S-1003']['urunler'][] = 'cetvel';

echo count($siparisler), "\n";                    // çıktı: 3
echo count($siparisler, COUNT_RECURSIVE), "\n";   // çıktı: 13

Destructuring: diziyi değişkenlere açmak

Destructuring, bir dizinin elemanlarını tek satırda ayrı değişkenlere aktarmanızı sağlar. PHP 7.1'den beri kısa [...] = $dizi yazımı kullanılabilir; eski list() yapısı da aynı işi görür. Numaralı açma her zaman 0 anahtarından başlar. Bir elemanı atlamak için o konumu boş bırakırsınız. İlişkisel dizilerde hangi anahtarın hangi değişkene gideceğini 'anahtar' => $degisken biçiminde yazarsınız; bu durumda sıra önemli değildir. İki değişkenin değerini geçici değişken kullanmadan takas etmek de bu yolla yapılır.

php
<?php
[$enlem, $boylam] = [41.01, 28.97];
echo "$enlem / $boylam\n";                 // çıktı: 41.01 / 28.97

[, $ikinci] = ['a', 'b', 'c'];
echo $ikinci, "\n";                        // çıktı: b

['ad' => $ad, 'sehir' => $sehir] = ['sehir' => 'Bursa', 'ad' => 'Mert'];
echo "$ad, $sehir\n";                      // çıktı: Mert, Bursa

$x = 1;
$y = 2;
[$x, $y] = [$y, $x];
echo "$x $y\n";                            // çıktı: 2 1

[[$p, $r], $s] = [[1, 2], 3];
echo $p + $r + $s, "\n";                   // çıktı: 6

list($ilk, $son) = ['başlangıç', 'bitiş'];
echo $son, "\n";                           // çıktı: bitiş

Destructuring, foreach ile birleştiğinde satır satır gelen veriyi okumayı çok kolaylaştırır. Döngü değişkeni yerine doğrudan bir açma kalıbı yazarsınız. Örnekteki ikinci satırda 30.0 değerinin 30 olarak yazdırıldığına dikkat edin: ondalık kısmı sıfır olan bir float metne çevrilirken nokta gösterilmez. Döngülerin diğer ayrıntıları için PHP döngüler yazısına bakabilirsiniz.

php
<?php
$satirlar = [
    [1, 'Kalem', 12.5],
    [2, 'Defter', 30.0],
];
foreach ($satirlar as [$id, $urun, $fiyat]) {
    echo "$id: $urun ($fiyat TL)\n";
}
/* çıktı:
1: Kalem (12.5 TL)
2: Defter (30 TL)
*/

Açmak istediğiniz anahtar dizide yoksa o değişken null olur ve normal bir erişimde olduğu gibi Undefined array key uyarısı verilir. Dizi olmayan bir değeri açmaya çalışırsanız bütün değişkenler null alır. PHP 8.5'in uyumsuzluk notlarına göre null dışındaki dizi olmayan değerleri açmak artık bir uyarı da üretir; daha önceki sürümler bunu sessizce geçiyordu.

php
<?php
[$a, $b, $c] = [1, 2];
var_dump($c);
/* çıktı:
Warning: Undefined array key 2 in /yol/ornek.php on line 2
NULL
*/

Spread operatörü ile dizi açma

PHP 7.4'ten beri bir dizi tanımının içinde ...$dizi yazarak başka bir dizinin elemanlarını yerinde açabilirsiniz. Aynı tanımda birden fazla açma yapılabilir, araya normal elemanlar da eklenebilir. Açma işlemi array_merge() mantığıyla çalışır: tam sayı anahtarlar yeniden numaralanır, aynı metin anahtarda sonra gelen değer öncekini ezer. PHP 8.1'den önce metin anahtarlı dizileri açmak Cannot unpack array with string keys hatası veriyordu; 8.1 ve sonrasında bu kısıt kalktı. Açılan değer bir dizi ya da Traversable arayüzünü uygulayan bir nesne olmalıdır.

+ operatörü, array_merge() ve spread farkı

+ operatörü, array_merge() ve spread farkı: $a + $b, array_merge($a, $b), [...$a, ...$b]

Üç yöntem de iki diziyi birleştirir ama çakışan anahtarlarda farklı davranır. + birleşim operatörüdür: soldaki dizi esas alınır, sağdaki diziden yalnızca solda olmayan anahtarlar eklenir. Bu yüzden iki numaralı listeyi + ile toplamak çoğu zaman beklenen sonucu vermez; [1, 2] + [3, 4] işleminin sonucu [1, 2] olur, çünkü 0 ve 1 anahtarları solda zaten vardır. array_merge() ve spread ise numaralı elemanları arka arkaya ekler, metin anahtarlarda sağdakini kazandırır.

Aşağıdaki örnekte çıktıyı kısa göstermek için json_encode() kullandık. Dikkat ederseniz + ile yazılan satırda anahtar sırası kullanıcı ayarıyla başlıyor; çünkü sonuç dizisi soldaki dizinin sırasını izler. Varsayılan ayarları kullanıcı ayarlarıyla birleştirmek + operatörünün en tipik kullanımıdır.

php
<?php
$varsayilan = ['dil' => 'tr', 'tema' => 'acik', 'sayfa' => 20];
$kullanici  = ['tema' => 'koyu'];

echo json_encode($kullanici + $varsayilan), "\n";
// çıktı: {"tema":"koyu","dil":"tr","sayfa":20}
echo json_encode(array_merge($varsayilan, $kullanici)), "\n";
// çıktı: {"dil":"tr","tema":"koyu","sayfa":20}
echo json_encode([...$varsayilan, ...$kullanici]), "\n";
// çıktı: {"dil":"tr","tema":"koyu","sayfa":20}

echo json_encode([1, 2] + [3, 4]), "\n";      // çıktı: [1,2]
echo json_encode([...[1, 2], ...[3, 4]]), "\n"; // çıktı: [1,2,3,4]
YöntemÇakışan metin anahtarTam sayı anahtarlarTipik kullanım
$a + $bsoldaki kalırkorunur, soldaki kalırvarsayılan değerleri tamamlamak
array_merge($a, $b)sağdaki kazanıryeniden numaralanır, eklenirlisteleri ve ayarları birleştirmek
[...$a, ...$b]sağdaki kazanıryeniden numaralanır, eklenirtanım içinde birleştirme, araya eleman ekleme

Liste mi, değil mi? array_is_list() ve JSON

array_is_list(), anahtarlar 0'dan count($dizi) - 1'e kadar sıralı ve boşluksuz ise true döndürür; boş dizi de liste sayılır. Bu ayrım en çok JSON üretirken önem kazanır: liste olan dizi JSON dizisine ([...]), liste olmayan dizi JSON nesnesine ({...}) çevrilir. Ortasından eleman silinmiş bir dizi bu yüzden API yanıtınızda bir anda nesneye dönüşebilir. JSON tarafının ayrıntıları PHP json_encode ve json_decode yazısında.

php
<?php
$x = ['a', 'b', 'c'];
unset($x[1]);

var_dump(array_is_list($x));               // çıktı: bool(false)
echo json_encode($x), "\n";                // çıktı: {"0":"a","2":"c"}

$x = array_values($x);
var_dump(array_is_list($x));               // çıktı: bool(true)
echo json_encode($x), "\n";                // çıktı: ["a","c"]

Başka tipleri diziye çevirmek

(array) dönüşümü bir int, float, string veya bool değeri 0 anahtarlı tek elemanlı bir diziye çevirir; null ise boş dizi olur. Bir nesneyi diziye çevirdiğinizde özellikleri anahtar olur, ancak private ve protected özelliklerin adlarına görünmeyen NUL baytları eklenir. Bu yüzden nesneleri diziye çevirmek için dönüşüm yerine sınıfa açık bir toArray() metodu yazmak daha öngörülebilir sonuç verir. Tiplerin genel tablosu için PHP veri tipleri yazısına bakabilirsiniz.

php
<?php
var_dump((array) 'merhaba');
var_dump((array) null);
/* çıktı:
array(1) {
  [0]=>
  string(7) "merhaba"
}
array(0) {
}
*/

Sık yapılan hatalar

  • Anahtarı tırnaksız yazmak: $dizi[ad] yazımında ad bir sabit adı olarak yorumlanır. PHP 8'de böyle bir sabit yoksa program Error ile durur. Çift tırnaklı metin içindeki "$dizi[ad]" yazımı ise geçerlidir; bu istisna yalnızca metin içi değişken yerleştirmeye özgüdür.
  • unset() sonrası numaraların kaydığını sanmak: silme işlemi diziyi yeniden numaralamaz. Sıralı liste gerekiyorsa array_values() çağırın.
  • İki listeyi + ile birleştirmek: numaralı listelerde + yalnızca eksik anahtarları ekler. Liste birleştirmek için array_merge() veya spread kullanın.
  • '08' ile 8 anahtarının aynı olduğunu varsaymak: başında sıfır olan metin tam sayıya çevrilmez; posta kodu veya ürün kodu gibi değerlerde iki ayrı anahtar oluşur.
  • Diziyi fonksiyon içinde değiştirip dışarıda değişmesini beklemek: dizi parametreleri kopya olarak geçer; değişikliği return ile döndürün veya bilinçli olarak referans parametresi kullanın.
  • Karmaşık veri için dizi ile yetinmek: kuyruk, yığın veya sabit boyutlu veri yapısı gerekiyorsa SPL veri yapıları daha uygun olabilir.
php
<?php
$ayar = ['dil' => 'tr'];
echo "Dil: $ayar[dil]\n";    // çıktı: Dil: tr  (metin içinde geçerli)
echo $ayar[dil];
/* çıktı:
Fatal error: Uncaught Error: Undefined constant "dil" in /yol/ornek.php:4
Stack trace:
#0 {main}
  thrown in /yol/ornek.php on line 4
*/

Sık Sorulan Sorular

PHP dizisinin boyutunu önceden belirtmem gerekir mi?

Hayır. PHP dizileri dinamik olarak büyür ve küçülür; eleman ekledikçe yer açılır. Sabit boyutlu ve yalnızca tam sayı indeksli bir yapı istiyorsanız SPL'deki SplFixedArray sınıfına bakabilirsiniz.

Bir dizinin boş olup olmadığını nasıl kontrol ederim?

En açık yol count($dizi) === 0 ya da $dizi === [] karşılaştırmasıdır. empty($dizi) de boş dizi için true döndürür, ancak değişken hiç tanımlı değilse de uyarı vermeden true döndüreceği için yazım hatalarını gizleyebilir.

Dizi anahtarları büyük/küçük harfe duyarlı mı?

Evet. Metin anahtarlar bayt bayt karşılaştırılır; 'Ad' ile 'ad' iki ayrı anahtardır. Türkçe karakterli anahtarlar da sorunsuz çalışır, fakat kullanıcıdan gelen metni anahtar yapacaksanız önce tutarlı bir biçime (örneğin küçük harfe) getirmeniz gerekir; Türkçe büyük/küçük harf dönüşümünün tuzakları PHP mbstring ve Türkçe karakterler yazısında.

list() ile [] destructuring arasında fark var mı?

İşlev olarak aynıdırlar; ikisi de anahtar belirtmeyi, eleman atlamayı ve iç içe açmayı destekler. Kısa [] yazımı PHP 7.1'den beri vardır ve modern kodda daha yaygındır. Aynı ifadede ikisini karıştırmak ise mümkün değildir.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: PHP öğrenme rehberi · PHP dizi fonksiyonları · PHP dizi sıralama · PHP döngüler · PHP referanslar · Undefined array key uyarısı