Ders 08 / 14
Çok Boyutlu Diziler
Dizilerin dizilerle iç içe kurulması; eksik bir iç anahtarın E_WARNING ile null vermesi; null üzerinde dizi erişimi; boşluk birleştirme işlecinin yolun tamamını sessize çevirmesi; okuma ile yazmanın ayrı kanal olması.
Yayın Güncelleme
Bu derste
- Dizi elemanı olarak dizi kullanarak iç içe veri modelini kurar ve her düzeyde anahtarla erişir
- Eksik iç anahtarın E_WARNING ve null ürettiğini ölçer ve uyarı sınıfına yazar
- Boşluk birleştirme işlecinin yolun tamamını sessize çevirdiğini ve okuma ile yazmanın ayrı kanal olduğunu gösterir
İçindekiler
İndeksli ve İlişkisel Diziler dersi, aynı anahtarın farklı yazımlarının tek elemana inmesini ve bunun hiçbir kanaldan duyulmadığını ölçtü. Anahtar tek bir değerdi. Bir elemanın kendisi başka bir dizi olduğunda erişim bir yola dönüşür: $a[0]['soyad'] iki ayrı arama yapar ve ikincisinin dayanağı birincinin sonucudur. Bu ders yolun bir halkası eksik olduğunda bunun nereden duyulduğunu ölçüyor.
Çok boyutlu dizi (multidimensional array) ayrı bir tip değildir; elemanları dizi olan sıradan bir dizidir. Derinlik için dilde bir sınır konmaz, yalnız bellek sınırlar. Ders sınıf adlarını önceki derslerdeki anlamıyla kullanır: sessiz, dönüş, uyarı, durdurur.
İç İçe Veri Modelleme
Bir öğrenci listesi, her öğrencinin adı ve not tablosuyla birlikte iç içe bir yapıya oturur. Aşağıdaki dosya bu yapıyı kuruyor, iki düzeyden okuyor ve count ile düz sayımı özyinelemeli sayımla karşılaştırıyor.
<?php // ogrenciler.php — dizi icinde dizi ile veri modelleme $ogrenciler = [ ['ad' => 'Ada', 'notlar' => ['mat' => 80, 'fen' => 90]], ['ad' => 'Can', 'notlar' => ['mat' => 70, 'fen' => 60]], ]; foreach ($ogrenciler as $sira => $ogrenci) { $ortalama = array_sum($ogrenci['notlar']) / count($ogrenci['notlar']); echo $sira, ' ', $ogrenci['ad'], ' ', $ortalama, "\n"; } echo 'Can fen: ', $ogrenciler[1]['notlar']['fen'], "\n"; echo 'duz sayim: ', count($ogrenciler), "\n"; echo 'ozyinelemeli sayim: ', count($ogrenciler, COUNT_RECURSIVE), "\n";
0 Ada 85 1 Can 65 Can fen: 60 duz sayim: 2 ozyinelemeli sayim: 10
Her düzey kendi anahtar uzayına sahiptir. Dış dizi indeksli, öğrenci kaydı ilişkisel, not tablosu yine ilişkisel; $ogrenciler[1]['notlar']['fen'] üç anahtarın sırayla uygulanmasıdır. count yalnız dış düzeyi sayar, COUNT_RECURSIVE bayrağı her iç diziyi hem bir eleman olarak hem içeriğiyle sayar; bu yüzden iki sayı arasındaki fark yapının derinliğini yansıtır, veri sayısını değil.
DZ6. Bu derste kayıtlar sabit biçimlidir: her öğrencide ad ve notlar anahtarı vardır. Yolun bozulduğu durumlar bir sonraki bölümde ayrıca kurulur. Bir kaydın biçiminin kullanıcıdan ya da dış bir kaynaktan geldiği durumlar M16/K01’in konusudur ve burada ele alınmaz.
Eksik İç Anahtar
Yol bir halkada kopunca ne olduğu, dinleyicinin kanal sırasıyla ölçülür. Dersin ortak yardımcısı kanal.php aşağıda tam metniyle veriliyor; çıktı bloğu olmadığı için yalnız diske yazılır.
<?php // kanal.php — bir sorunun hangi kanaldan duyuldugunu siniflandiran yardimcilar // Yakalanan uyarilarin seviye adlari burada birikir; ileti metni tutulmaz. $GLOBALS['duyulan_uyarilar'] = []; set_error_handler(function (int $seviye): bool { $adlar = [E_WARNING => 'E_WARNING', E_NOTICE => 'E_NOTICE', E_DEPRECATED => 'E_DEPRECATED']; $GLOBALS['duyulan_uyarilar'][] = $adlar[$seviye] ?? 'E_' . $seviye; return true; }); // Degeri tipiyle birlikte kisa bir metne cevirir. function yaz(mixed $deger): string { return match (true) { $deger === null => 'null', is_bool($deger) => $deger ? 'true' : 'false', is_array($deger) => 'dizi(' . count($deger) . ')', default => get_debug_type($deger) . ' ' . $deger, }; } // Isi calistirir ve sorunun hangi kanaldan duyuldugunu sirayla sorar: // once firlatma, sonra uyari, sonra false/null donus; hicbiri yoksa sessiz. function dinle(callable $is): array { $GLOBALS['duyulan_uyarilar'] = []; try { $sonuc = $is(); } catch (Throwable $hata) { return ['durdurur', get_class($hata)]; } if ($GLOBALS['duyulan_uyarilar']) { $seviyeler = implode(',', array_unique($GLOBALS['duyulan_uyarilar'])); return ['uyari', $seviyeler . ', sonuc ' . yaz($sonuc)]; } if ($sonuc === false || $sonuc === null) { return ['donus', 'sonuc ' . yaz($sonuc)]; } return ['sessiz', 'sonuc ' . yaz($sonuc)]; } // Kodu ayri bir PHP yurutmesinde calistirir; cikis kodu 255 ise yurutme durmustur. function ayri_yurut(string $kod): array { exec('php -d display_errors=0 -r ' . escapeshellarg($kod) . ' 2>&1', $satirlar, $cikis); $sinif = $cikis === 255 ? 'durdurur' : 'sessiz'; return [$sinif, 'cikti ' . count($satirlar) . ' satir, cikis ' . $cikis]; }
<?php // eksik.php — eksik ic anahtar ve null uzerinde dizi erisimi require 'kanal.php'; $kayitlar = [['ad' => 'Ada']]; $gozlemler = [ 'eksik ic anahtar' => fn() => $kayitlar[0]['soyad'], 'eksik dis anahtar' => fn() => $kayitlar[5]['ad'], 'null uzerinde erisim' => fn() => $kayitlar[5]['ad']['x'], 'dizgi uzerinde erisim' => fn() => $kayitlar[0]['ad']['x'], ]; foreach ($gozlemler as $ad => $gozlem) { [$sinif, $kanit] = dinle($gozlem); printf("%-23s%-9s%s\n", $ad, $sinif, $kanit); }
eksik ic anahtar uyari E_WARNING, sonuc null eksik dis anahtar uyari E_WARNING, sonuc null null uzerinde erisim uyari E_WARNING, sonuc null dizgi uzerinde erisim durdurur TypeError
Birinci satır kursun eksik ic anahtar gözlemidir: $kayitlar[0]['soyad'] değeri null verdi ve E_WARNING bildirdi. Sınıf uyarı. Yürütme sürdü; sonuç null olduğu için çağıran kod hata olduğunu ancak değerle birlikte gelen uyarıdan anlar. Önceki dersin sessizliğiyle bu ders arasındaki ayrım budur: anahtar yazımındaki kayıp duyulmuyordu, anahtar okumadaki kayıp duyuluyor.
İkinci satır dış düzeyden eksik bir indeks için aynı sonucu veriyor, üçüncü satır ise zincirin ilk halkası zaten null iken ikinci erişimin de aynı seviyeyi bildirdiğini gösteriyor: null üzerinde dizi erişimi hata değil uyarıdır ve null yine null döner. Zincir ne kadar uzarsa uzasın bir kopukluk sonrasındaki her erişim sessizce null’a çıkar; kopukluğun hangi halkada olduğu uyarı metninden okunur, sonuçtan okunmaz. Dördüncü satır sınırı gösteriyor: yol bir dizgiye vardığında ve dizgiye 'x' gibi bir dizgi anahtarı uygulandığında null dönmez, TypeError fırlar; sınıf durdurur. Uyarı kanalı yalnız null ya da eksik anahtar için işler, tipi yanlış bir değere uygulanan erişim için işlemez.
DZ7. Uyarının ileti metni ve satır bilgisi ortama bağlıdır ve ders onları basmaz; yalnız seviye adı (E_WARNING) ve sonucun tipi basılır. Aynı kopukluğun bir ayarla durduran bir hataya çevrilmesi mümkündür, ancak ders hiçbir ini değerine güvenmez ve bu yolu ölçmez.
Boşluk Birleştirme ile Sessizlik
Boşluk birleştirme işleci (null coalescing, ??) sol tarafın değerini, o null ya da tanımsız ise sağ tarafı verir. Eksik yol üzerinde uygulandığında zincirin her halkasındaki uyarıyı bastırır.
<?php // birlestirme.php — ?? eksik yolu sessize cevirir require 'kanal.php'; $veri = ['a' => 1]; $kayitlar = [['ad' => 'Ada']]; $gozlemler = [ 'uyarili okuma' => fn() => $veri['b'], 'birlestirmeli' => fn() => $veri['b'] ?? 0, 'derin birlestirme' => fn() => $kayitlar[3]['notlar']['fen'] ?? -1, 'var olan deger' => fn() => $kayitlar[0]['ad'] ?? 'yok', ]; foreach ($gozlemler as $ad => $gozlem) { [$sinif, $kanit] = dinle($gozlem); printf("%-19s%-9s%s\n", $ad, $sinif, $kanit); }
uyarili okuma uyari E_WARNING, sonuc null birlestirmeli sessiz sonuc int 0 derin birlestirme sessiz sonuc int -1 var olan deger sessiz sonuc string Ada
Aynı eksik anahtar iki kanalda duyuldu: yalın okuma uyarı, ?? ile sessiz. Üçüncü satır daha önemli: ?? yalnız son halkayı değil, yolun tamamını sarar; üç düzeyli bir yolda herhangi bir halka eksikse sonuç varsayılan değerdir ve hiçbir kanaldan haber gelmez. Bu işlecin amacıdır, ancak amaç sorunun kaybolması anlamına da gelir: yol yanlış yazılmışsa ('not' yerine 'notlar'), ?? yazımı hatayı da aynı sessizlikle örter.
Kayıt Listesi ile Çalışmak
İç içe diziler pratikte çoğu zaman bir kayıt listesi biçimindedir: dış dizi indeksli, her eleman aynı anahtarları taşıyan ilişkisel bir dizi. Bu biçim için üç sık iş vardır: bir sütunu çekmek, kayıtları bir anahtara göre sıralamak, kayıtları o sütuna göre indekslemek.
<?php // kayitlar.php — kayit listesinde sutun, siralama ve indeksleme $kayitlar = [ ['id' => 7, 'ad' => 'Can', 'yas' => 31], ['id' => 3, 'ad' => 'Ada', 'yas' => 36], ['id' => 9, 'ad' => 'Efe', 'yas' => 24], ]; echo 'adlar: ', implode(',', array_column($kayitlar, 'ad')), "\n"; echo 'id ile indeksli: ', implode(',', array_keys(array_column($kayitlar, 'ad', 'id'))), "\n"; usort($kayitlar, fn($sol, $sag) => $sol['yas'] <=> $sag['yas']); echo 'yasa gore: ', implode(',', array_column($kayitlar, 'ad')), "\n"; $kayitlar[1]['yas'] += 1; echo 'guncel yas: ', $kayitlar[1]['yas'], "\n"; echo 'ortalama yas: ', array_sum(array_column($kayitlar, 'yas')) / count($kayitlar), "\n";
adlar: Can,Ada,Efe id ile indeksli: 7,3,9 yasa gore: Efe,Can,Ada guncel yas: 32 ortalama yas: 30.666666666667
array_column bir sütunu düz bir diziye çevirir; üçüncü argüman verilirse sonucun anahtarları o sütundan gelir. usort kayıtları verilen karşılaştırmaya göre yeniden diziler ve anahtarları yeniden numaralar. Ardından $kayitlar[1]['yas'] += 1 yazımı iki düzeyli bir yola yazıyor; yol var olduğu için hiçbir şey bildirilmiyor. Kayıt listesi ile çalışan kodun çoğu bu üç fonksiyonla ve iki düzeyli indekslemeyle yazılır; hata, kayıtlar aynı biçimde olmadığında ortaya çıkar.
DZ8. Kayıtların biçimi bu derste kod içinde sabittir. Aynı listeyi bir dosyadan ya da bir istekten okuyan kodun kayıt biçimini doğrulaması gerekir; bu doğrulama burada yapılmaz; kayıt biçimini sınayan fonksiyon bu dersin kapsamı dışındadır.
Bir kaydın bir anahtarı eksik olduğunda, sütunu çekmek ile her kayıttan anahtarı tek tek okumak ayrı kanallardan duyulur.
<?php // eksiksutun.php — array_column eksik anahtari sessizce atlar require 'kanal.php'; $kayitlar = [ ['ad' => 'Ada', 'soyad' => 'Yilmaz'], ['ad' => 'Can'], ['ad' => 'Efe', 'soyad' => 'Kaya'], ]; $gozlemler = [ 'array_column' => fn() => array_column($kayitlar, 'soyad'), 'tek tek okuma' => fn() => array_map(fn($k) => $k['soyad'], $kayitlar), 'birlesimli okuma' => fn() => array_map(fn($k) => $k['soyad'] ?? '-', $kayitlar), ]; foreach ($gozlemler as $ad => $gozlem) { [$sinif, $kanit] = dinle($gozlem); printf("%-17s%-9s%s\n", $ad, $sinif, $kanit); } echo 'sutun uzunlugu: ', count(array_column($kayitlar, 'soyad')), "\n"; echo 'kayit sayisi: ', count($kayitlar), "\n";
array_column sessiz sonuc dizi(2) tek tek okuma uyari E_WARNING, sonuc dizi(3) birlesimli okuma sessiz sonuc dizi(3) sutun uzunlugu: 2 kayit sayisi: 3
array_column eksik anahtarı olan kaydı sessizce atladı: sütun üç yerine iki eleman taşıyor ve sessiz sınıfındadır. Tek tek okuma aynı kayıtta E_WARNING verdi ve uyarı sınıfındadır; ?? ile okuma ise yedek değeri verip sessizleşti. Üç yazım aynı eksikliğe üç farklı tepki gösterdi. Dikkat edilecek yer şudur: array_column sonucu ile kayıt listesi artık aynı uzunlukta değildir, bu yüzden ikisini indeksle eşleştiren bir kod sessizce yanlış kaydı eşleştirir.
Dizi Açma ve Özyinelemeli Birleştirme
İç içe bir dizinin parçalarını değişkenlere dağıtan dizi açma (destructuring) yazımı, yolun eksik olduğu durumda da kendi kanalını kullanır. İç içe iki dizinin birleştirilmesi ise düz birleştirmeden ayrı fonksiyonlarla yapılır.
<?php // acma.php — dizi acma ve ozyinelemeli birlestirme require 'kanal.php'; $gozlemler = [ 'tam acma' => fn() => (function () { [$x, $y] = [1, 2]; return $x + $y; })(), 'eksik indeks' => fn() => (function () { [$x, $y] = [1]; return $y; })(), 'eksik anahtar' => fn() => (function () { ['ad' => $ad, 'yas' => $yas] = ['ad' => 'Ada']; return $yas; })(), 'ic ice acma' => fn() => (function () { [[$p, $q], [$r]] = [[1, 2], [3]]; return $p + $q + $r; })(), 'eksik ic acma' => fn() => (function () { [[$p], [$r]] = [[1]]; return $r; })(), ]; foreach ($gozlemler as $ad => $gozlem) { [$sinif, $kanit] = dinle($gozlem); printf("%-15s%-9s%s\n", $ad, $sinif, $kanit); } $sol = ['a' => ['x' => 1, 'y' => 2], 'b' => 3]; $sag = ['a' => ['y' => 20, 'z' => 30], 'b' => 4]; echo 'array_merge: ', json_encode(array_merge($sol, $sag)), "\n"; echo 'array_replace: ', json_encode(array_replace($sol, $sag)), "\n"; echo 'array_replace_recursive: ', json_encode(array_replace_recursive($sol, $sag)), "\n"; echo 'array_merge_recursive: ', json_encode(array_merge_recursive($sol, $sag)), "\n";
tam acma sessiz sonuc int 3
eksik indeks uyari E_WARNING, sonuc null
eksik anahtar uyari E_WARNING, sonuc null
ic ice acma sessiz sonuc int 6
eksik ic acma uyari E_WARNING, sonuc null
array_merge: {"a":{"y":20,"z":30},"b":4}
array_replace: {"a":{"y":20,"z":30},"b":4}
array_replace_recursive: {"a":{"x":1,"y":20,"z":30},"b":4}
array_merge_recursive: {"a":{"x":1,"y":[2,20],"z":30},"b":[3,4]}
Dizi açma, eksik indekste ya da eksik anahtarda E_WARNING verir ve değişken null kalır; yani doğrudan indeksle okumanın uyarı sınıfı açmada da geçerlidir. Tam eşleşen açma ve iç içe açma sessizdir.
Özyinelemeli birleştirmede dört fonksiyon üç ayrı sonuç verir. array_merge ve array_replace iç dizileri bütün olarak değiştirir, x anahtarı kaybolur. array_replace_recursive iç dizilere iner ve x’i korur. array_merge_recursive ise çakışan skaler değerleri dizi hâline getirir: y için [2,20], b için [3,4]. Toplam değerin tipinin sessizce değişmesi, sonradan b’yi sayı varsayan kodu bozabilecek bir ayrıntıdır.
Sınırlayıcı Ölçüm
Eksik yola okumak uyarı veriyordu. Aynı eksik yola yazmak ise ayrı bir kanaldır.
<?php // yazma.php — eksik yola yazma ve okuma ayri kanal require 'kanal.php'; $gozlemler = [ 'bos diziye derin yazma' => function () { $a = []; $a['x']['y'] = 1; return $a; }, 'ayni yoldan okuma' => function () { $a = []; return $a['x']['y']; }, 'varolan skalere yazma' => function () { $a = ['x' => 5]; $a['x']['y'] = 1; return $a; }, ]; foreach ($gozlemler as $ad => $gozlem) { [$sinif, $kanit] = dinle($gozlem); printf("%-24s%-9s%s\n", $ad, $sinif, $kanit); } $a = []; $a['x']['y'] = 1; echo 'kurulan yapi: ', json_encode($a), "\n";
bos diziye derin yazma sessiz sonuc dizi(1)
ayni yoldan okuma uyari E_WARNING, sonuc null
varolan skalere yazma durdurur Error
kurulan yapi: {"x":{"y":1}}
Boş bir diziye $a['x']['y'] = 1 yazmak iç diziyi kendiliğinden kurar ve hiçbir seviye bildirmez: sınıf sessiz. Aynı yoldan okumak ise uyarı verir. Okuma ve yazma ayrı kanallardır; birinde duyulan sorun diğerinde duyulmaz. Üçüncü satır ayrımın sınırını çiziyor: yol üzerindeki mevcut değer bir skaler ise, yazma artık kendiliğinden kurmaz ve durdurur.
DZ9. Yazmanın sessizliği bir kolaylık olarak tasarlanmıştır ve yanlış yazılmış bir anahtarda yeni bir dal kurar: $a['notlr']['mat'] = 90 hata vermez, yanında yeni bir notlr dalı açar. Bu ders o dalın sonradan kim tarafından okunduğunu izlemez; ölçülen yalnız yazma anında hiçbir kanaldan haber gelmediğidir.
Özet
- Çok boyutlu dizi ayrı bir tip değil, elemanları dizi olan dizidir; erişim yol boyunca anahtarların sırayla uygulanmasıdır.
countyalnız dış düzeyi sayar;COUNT_RECURSIVEiç dizileri hem eleman hem içerik olarak sayar.- Eksik iç anahtar
nulldöndürür veE_WARNINGbildirir; bu dersin ölçü sınıfı uyarıdır (eksik ic anahtar). nullüzerinde dizi erişimi deE_WARNINGverir venulldöner; kopukluktan sonraki her halka sessizcenullüretir.??yolun tamamını sessize çevirir; yanlış yazılmış yolu da aynı sessizlikle örter.- Okuma ile yazma ayrı kanaldır: eksik yoldan okumak uyarı verir, boş diziye derin yazmak iç diziyi sessizce kurar.
Sonraki Adım
Bu ders bir yolun kopukluğunu null ve uyarı olarak ölçtü. Dizi Fonksiyonları dersinde kanal değişiyor: bir eleman aramak, bulunamadığında uyarı vermiyor, bir değer dönüyor; ve o değer, bulunan ilk elemanın dönüşüyle gevşek karşılaştırmada karışabiliyor.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.