
PHP'de JSON İşlemleri: encode, decode ve Veri Değişimi
JSON, uygulamalar arası veri değişiminin ortak biçimidir. PHP'nin sunduğu iki fonksiyon işi büyük ölçüde halleder, ancak varsayılan davranışları üretim için uygun değildir: hata durumunda istisna fırlatılmaz, Türkçe karakterler kaçış dizilerine çevrilir ve derinlik sınırı sessizce uygulanır.
Bu bölümde kodlama ve çözümleme bayrakları, hata yönetimi, nesnelerin JSON karşılığının tanımlanması ve gelen istek gövdesinin güvenli işlenmesi ele alınıyor.
Kodlama ve bayraklar
Varsayılan çıktıda Türkçe karakterler ve eğik çizgiler kaçırılır. Sonuç geçerli JSON'dur, ancak okunması güçtür ve gereksiz yer kaplar. Bayraklar bu davranışı düzeltir.
$veri = ['baslik' => 'Kaz Dağları', 'adres' => '/yazi/kaz-daglari'];
echo json_encode($veri);
// {"baslik":"Kaz Da\u011flar\u0131","adres":"\/yazi\/kaz-daglari"}
echo json_encode($veri, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
// {"baslik":"Kaz Dağları","adres":"/yazi/kaz-daglari"}Hata durumunda fonksiyon false döndürür ve bu değer sessizce boş çıktıya dönüşebilir. İstisna bayrağı kullanılarak sorun görünür hale getirilir.
try {
$cikti = json_encode($veri, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE);
} catch (JsonException $e) {
// en sık neden: geçersiz UTF-8 baytları ya da kaynak tipinde değer
throw new RuntimeException('Yanıt üretilemedi', previous: $e);
}Okunabilir çıktı yalnızca hata ayıklama ve yapılandırma dosyalarında kullanılır. API yanıtlarında girinti eklemek, yanıt boyutunu bir kazanç sağlamadan büyütür.
Çözümleme
İkinci parametre çıktının biçimini belirler. Birleşimli dizi, alanlara erişimi kolaylaştırır; nesne dönüşü ise alan adları geçerli birer değişken adı olmadığında sorun çıkarır.
$veri = json_decode($ham, associative: true, flags: JSON_THROW_ON_ERROR);
// derinlik sınırı, iç içe yapılarda beklenmedik girdiye karşı korur
$veri = json_decode($ham, true, depth: 32, flags: JSON_THROW_ON_ERROR);
// büyük tam sayılar ondalığa dönüşerek duyarlılık kaybetmesin
$veri = json_decode($ham, true, flags: JSON_BIGINT_AS_STRING | JSON_THROW_ON_ERROR);Çözümleme sonucunda dönen değer her zaman dizi olmaz. Gövde tek bir sayı ya da metin içeriyorsa sonuç da o tipte olur; bu yüzden beklenen yapı açıkça denetlenmelidir. Geçerli JSON olan null metni de null döndürür ve hatalı çözümlemeden ayırt edilmesi gerekir.
Yalnızca geçerliliğin sorgulandığı durumlarda, tüm yapıyı belleğe almadan denetim yapan fonksiyon kullanılır. Bu, büyük gövdelerde belirgin bellek kazancı sağlar.
if (!json_validate($ham)) { // PHP 8.3 ile geldi
http_response_code(400);
exit;
}Nesneleri JSON'a çevirmek
Bir nesne doğrudan kodlandığında yalnızca dışarı açık özellikleri çıktıya girer. Çıktının biçimini denetlemek için ilgili arayüz uygulanır; böylece iç yapı ile dış sözleşme birbirinden ayrılır.
final class Yazi implements JsonSerializable
{
public function __construct(
private readonly int $id,
private readonly string $baslik,
private readonly DateTimeImmutable $olusturma,
private readonly string $icPano, // dışarı verilmeyecek alan
) {}
public function jsonSerialize(): array
{
return [
'id' => $this->id,
'baslik' => $this->baslik,
'olusturma' => $this->olusturma->format(DATE_ATOM),
];
}
}
echo json_encode(new Yazi(1, 'Örnek', new DateTimeImmutable(), 'gizli'),
JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE);Bu ayrım önemlidir: iç yapıdaki bir alan adı değiştiğinde, dönüşüm metodu güncellenerek dış sözleşme korunur. Nesnenin doğrudan kodlanması durumunda ise her yeniden adlandırma, API tüketicilerini kıran bir değişikliğe dönüşür.
Değer taşıyan enumlar kendiliğinden kendi değerlerine dönüşür. Değer taşımayan enumlar kodlanamaz; API yanıtında kullanılacak enumların değerli tanımlanması bu yüzden pratik bir kuraldır.
Gelen isteği okumak
JSON gövdesiyle gelen istekler süper globallerde bulunmaz; gövde ham akıştan okunur. İçerik türü denetlenmeli ve çözümleme başarısız olduğunda uygun durum kodu döndürülmelidir.
$tur = $_SERVER['CONTENT_TYPE'] ?? '';
if (!str_starts_with($tur, 'application/json')) {
http_response_code(415);
exit;
}
$ham = file_get_contents('php://input');
try {
$veri = json_decode($ham, true, 32, JSON_THROW_ON_ERROR);
} catch (JsonException) {
http_response_code(400);
echo json_encode(['hata' => 'Gövde geçerli JSON değil']);
exit;
}
if (!is_array($veri)) {
http_response_code(400);
exit;
}Çözümlenen veri doğrulanmadan kullanılmaz. Alanların varlığı, tipi ve değer aralığı denetlenmelidir; gövdenin JSON olması içeriğinin beklenen yapıda olduğunu göstermez.
$baslik = $veri['baslik'] ?? null;
if (!is_string($baslik) || mb_strlen(trim($baslik)) < 3) {
http_response_code(422);
echo json_encode(['hata' => 'baslik en az üç karakter olmalı'], JSON_UNESCAPED_UNICODE);
exit;
}Sayılar ve duyarlılık
JSON tarafında tam sayı ile ondalık sayı ayrımı biçimden anlaşılır. PHP'nin ondalık sayıları ikilik tabanda saklaması nedeniyle, para tutarlarının JSON üzerinden ondalık olarak taşınması yuvarlama farklarına yol açabilir. Tutarlar en küçük birimde tam sayı olarak ya da metin biçiminde taşınmalıdır.
echo json_encode(['tutar' => 0.1 + 0.2]); // {"tutar":0.30000000000000004}
echo json_encode(['tutar_kurus' => 30]); // {"tutar_kurus":30}Çok büyük tam sayılar da dikkat gerektirir. JavaScript tarafında güvenli tam sayı aralığının üzerindeki kimlik değerleri duyarlılık kaybeder; bu tür değerler metin olarak gönderilmelidir.
Boş dizilerin kodlanması da sık karşılaşılan bir karışıklık kaynağıdır. PHP tarafında dizi hem liste hem eşleme olabildiği için, boş bir dizi köşeli parantezle kodlanır ve nesne bekleyen tüketici tarafında hata oluşabilir. Nesne beklendiği kesin olan yerlerde ilgili bayrak kullanılır.
echo json_encode(['ayarlar' => []]); // {"ayarlar":[]}
echo json_encode(['ayarlar' => []], JSON_FORCE_OBJECT); // {"ayarlar":{}}
// anahtarları sıralı olmayan diziler de nesne olarak kodlanır
echo json_encode([1 => 'a', 3 => 'b']); // {"1":"a","3":"b"}Yanıt üretmek
JSON yanıtı üretirken içerik türü başlığı, karakter kümesi ve durum kodu birlikte ayarlanır. Bu üçlü tek bir yardımcı fonksiyonda toplandığında, her uçta aynı biçimin kullanılması sağlanır.
function jsonYanit(array $govde, int $kod = 200): never
{
http_response_code($kod);
header('Content-Type: application/json; charset=utf-8');
echo json_encode(
$govde,
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR,
);
exit;
}
jsonYanit(['ok' => true, 'id' => $yeniId], 201);Hata yanıtlarının da aynı yapıda olması, tüketen tarafın tek bir çözümleme kodu yazmasını sağlar. Durum kodu ile gövdedeki bilgi çelişmemelidir; başarısız bir işlemin 200 koduyla dönmesi, istemci tarafında hata denetiminin atlanmasına yol açar.
Büyük veri kümeleri
Tek bir JSON dizisinde binlerce kayıt taşımak, hem üreten hem tüketen tarafta tüm verinin belleğe alınmasını gerektirir. Bu tür aktarımlarda satır başına bir JSON nesnesi yazan biçim tercih edilir; okuyucu dosyayı satır satır işleyebilir.
$cikti = fopen('php://output', 'w');
foreach ($kayitlar as $kayit) {
fwrite($cikti, json_encode($kayit, JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR) . "
");
}
fclose($cikti);Bu biçimde her satır kendi başına geçerli bir JSON belgesidir. Aktarım yarıda kesilse bile okunabilen satırlar işlenebilir, bellek kullanımı kayıt sayısından bağımsız kalır.
Kontrol listesi
- Kodlama ve çözümlemede
JSON_THROW_ON_ERRORkullanılıyor. - Türkçe içerikte
JSON_UNESCAPED_UNICODEetkin. - Çözümlemede derinlik sınırı açıkça veriliyor.
- Nesneler
JsonSerializableile dış sözleşmeyi kendisi tanımlıyor. - Gelen isteklerde içerik türü denetleniyor, hatalarda doğru durum kodu dönüyor.
- Çözümlenen veri alan alan doğrulanıyor.
- Para ve büyük kimlik değerleri ondalık sayı olarak taşınmıyor.
İlgili yazılar
PHP eğitim serisi
Bu yazı, temel sözdiziminden üretim ortamına kadar ilerleyen 25 bölümlük serinin bir parçası. Bölümler sırayla okunacak biçimde hazırlandı, ancak her biri tek başına da kullanılabilir.
Temeller
- Kurulum ve temel sözdizimi
- Döngüler ve akış kontrolü
- Diziler
- Fonksiyonlar
- String fonksiyonları
- Süper globaller
- Form işleme
- Dosya işlemleri
Dilin ayrıntıları
Nesne yönelimli PHP
- Sınıf ve nesne
- Kalıtım, arayüz ve trait
- Statik üyeler, sabitler ve enum
- Namespace, Composer ve autoload
Veri ve güvenlik
- PDO ile veritabanı işlemleri
- Oturum yönetimi ve kimlik doğrulama
- Güvenli çıktı ve XSS
- JSON ile veri değişimi (bu yazı)
Dış dünya ve üretim
Yorumlar
İlk yorumu sen yap.
İlgili Yazılar

PHP Uygulamasını Üretime Almak: Yapılandırma ve Güvenlik
Geliştirme makinesinde çalışan kod ile üretimde güvenle çalışan kod arasındaki fark yapılandırmadır. Ayarlar, izinler, dağıtım akışı ve son kontroller.

PHP ile REST API Yazmak: Yönlendirme ve HTTP Durum Kodları
Bir API'nin kalitesi çoğunlukla ayrıntılarda belli olur: doğru durum kodu, tutarlı hata biçimi ve öngörülebilir adresler. Saf PHP ile uçtan uca kurulum.

PHPUnit ile Birim Test Yazmak: Kurulum, Sahte Nesneler ve Kapsam
Testin amacı hata bulmak değil, değişikliği güvenle yapabilmektir. Kurulum, ilk test, sahte nesneler ve test edilebilir kodun özellikleri.