PHP'de bir dosyayı tek seferde okumak için file_get_contents(), tek seferde yazmak için file_put_contents() kullanılır. Dosyayı satır satır işlemek, büyük dosyaları belleğe tamamen almadan okumak veya yazarken kilit tutmak gerektiğinde ise fopen() ile bir akış (stream) açar, fgets() ya da fwrite() ile çalışır ve işiniz bitince fclose() ile kapatırsınız. Satırları doğrudan diziye almak için file(), CSV için fgetcsv() ve fputcsv() vardır.
Bu yazıda bu fonksiyonların imzalarını, dönüş değerlerini ve hata durumlarını php.net kılavuzuna göre ele alıyoruz. Her örnek PHP 8.5.12 CLI ile çalıştırıldı ve çıktılar gerçek çıktıdır. Dosyaların hangi dizine göre çözüldüğü, false dönüşünün doğru kontrolü, FILE_APPEND ile LOCK_EX bayrakları ve PHP 8.4 ile gelen CSV uyarısı gibi sık karşılaşılan tuzaklar da ayrı başlıklarda anlatılıyor. Serinin genel planı için PHP öğrenme rehberi sayfasına bakabilirsiniz.
Tek seferde okuma ve yazma: file_get_contents ve file_put_contents

file_get_contents() dosyanın tamamını bir string olarak döndürür; başarısız olursa false döner. Kılavuz bu fonksiyonu bir dosyanın içeriğini string olarak almanın tercih edilen yolu olarak tanımlar ve işletim sistemi destekliyorsa bellek eşleme (memory mapping) tekniklerinden yararlandığını belirtir. İmzası şöyledir: file_get_contents(string $filename, bool $use_include_path = false, ?resource $context = null, int $offset = 0, ?int $length = null): string|false.
Yazma tarafındaki karşılığı file_put_contents(string $filename, mixed $data, int $flags = 0, ?resource $context = null): int|false fonksiyonudur. Kılavuza göre bu çağrı, sırayla fopen(), fwrite() ve fclose() çağırmakla aynı işi yapar. Dosya yoksa oluşturulur, varsa içeriği silinip yerine yeni veri yazılır. Başarılı olduğunda yazılan bayt sayısını döndürür.
<?php
$yazilan = file_put_contents('notlar.txt', "Ankara\nİzmir\n");
var_dump($yazilan); // çıktı: int(14)
$icerik = file_get_contents('notlar.txt');
var_dump($icerik);
/*
string(14) "Ankara
İzmir
"
*/Burada dikkat edilmesi gereken nokta, dönen sayının karakter değil bayt olmasıdır. "Ankara" 6 bayt, iki satır sonu 2 bayt eder; "İzmir" ise beş harfli olduğu hâlde UTF-8'de "İ" iki bayt tuttuğu için 6 bayttır. Toplam 14 bayt yapar. Her iki fonksiyon da kılavuzda "binary-safe" olarak işaretlidir; yani resim, PDF veya sıkıştırılmış dosya gibi ikili verileri de bozmadan okur ve yazar. Karakter sayısı gerekiyorsa mbstring fonksiyonları yazısındaki mb_strlen() kullanılmalıdır.
Dosyanın bir bölümünü okumak
offset ve length parametreleri dosyanın yalnızca belli bir parçasını okumanızı sağlar. PHP 7.1'den beri negatif offset desteklenir ve bu durumda sayım dosyanın sonundan yapılır. Aradaki parametreleri tek tek yazmak yerine isimli argüman kullanmak kodu okunur kılar. Kılavuz, uzak dosyalarda offset ile konumlanmanın desteklenmediğini de not eder.
<?php
file_put_contents('alfabe.txt', 'ABCDEFGHIJ');
var_dump(file_get_contents('alfabe.txt', false, null, 2, 3)); // çıktı: string(3) "CDE"
var_dump(file_get_contents('alfabe.txt', offset: -4)); // çıktı: string(4) "GHIJ"İsimli argümanların nasıl çalıştığını PHP fonksiyon tanımlama ve parametreler yazısında ayrıntılı bulabilirsiniz.
false dönüşünü doğru kontrol etmek
Dosya bulunamazsa file_get_contents() bir E_WARNING üretir ve false döndürür. Bir istisna (exception) fırlatılmaz; betik çalışmaya devam eder. Bu yüzden dönüş değerini kontrol etmeyen kod, sonraki satırlarda false değerini bir string gibi kullanmaya çalışır ve hatanın asıl kaynağı gözden kaçar.
<?php
$veri = file_get_contents('olmayan.txt');
var_dump($veri);
/*
Warning: file_get_contents(olmayan.txt): Failed to open stream: No such file or directory in /yol/ornek.php on line 2
bool(false)
*/Kılavuz bu fonksiyonların sayfalarında aynı uyarıyı tekrarlar: fonksiyon false dönebilir, ama false gibi değerlendirilen başka değerler de dönebilir. Boş bir dosya okunduğunda dönen boş string "", if (!$veri) kontrolünde hata gibi görünür. Benzer şekilde file_put_contents() boş bir string yazdığında 0 döndürür ve bu da gevşek kontrolde başarısızlık sanılır. Doğru yöntem her zaman === false ile katı karşılaştırma yapmaktır. Gevşek ve katı karşılaştırmanın farkı eşitlik ve karşılaştırma yazısında anlatılıyor.
Uyarıları istisnaya çevirip try/catch ile yakalamak isterseniz set_error_handler() ile ErrorException fırlatabilirsiniz; bu yöntem hata seviyeleri ve error_reporting yazısında, try/catch yapısı da try/catch ve exception yazısında ele alınıyor. Hataları @ operatörüyle susturmak ise sorunu çözmez, yalnızca gizler.
Ekleme ve kilit: FILE_APPEND ve LOCK_EX
file_put_contents() varsayılan olarak dosyanın üzerine yazar. Sona eklemek için FILE_APPEND bayrağı verilir. LOCK_EX ise yazma sırasında dosyaya özel (exclusive) kilit alır; kılavuz bunu, fopen() ile fwrite() arasına bir flock() çağrısı eklemek olarak açıklar. Bayraklar ikili VEYA operatörü | ile birleştirilir. $data parametresi tek boyutlu bir dizi de olabilir; bu, dizinin implode('', $dizi) ile birleştirilip yazılmasıyla aynı sonucu verir.
<?php
file_put_contents('kayit.log', "ilk satır\n");
file_put_contents('kayit.log', "ikinci satır\n", FILE_APPEND | LOCK_EX);
file_put_contents('kayit.log', ['üçüncü', ' satır', "\n"], FILE_APPEND | LOCK_EX);
echo file_get_contents('kayit.log');
/*
ilk satır
ikinci satır
üçüncü satır
*/Basit bir günlük (log) dosyası için bu kalıp çoğu zaman yeterlidir. Aynı anda birden çok isteğin aynı dosyaya yazabildiği durumlarda LOCK_EX vermek, satırların birbirine karışma riskini azaltır. Ancak bu kilit "advisory" türdendir: Kılavuz, dosyaya erişen tüm programların aynı kilitleme yöntemini kullanması gerektiğini, aksi hâlde kilidin işe yaramayacağını belirtir. Windows'ta ise flock() zorunlu (mandatory) kilit kullanır.
Satırları diziye almak: file()
file() dosyayı okur ve her satırı bir dizi elemanı olarak döndürür. Varsayılan durumda her elemanın sonunda satır sonu karakteri durur; bu, karşılaştırma yaparken en sık yapılan hatalardan biridir. FILE_IGNORE_NEW_LINES bayrağı satır sonlarını atar, FILE_SKIP_EMPTY_LINES boş satırları atlar. PHP 8.3'ten beri flags içinde geçersiz bir değer (örneğin FILE_APPEND) verirseniz ValueError fırlatılır.
<?php
file_put_contents('sehirler.txt', "Ankara\n\nBursa\nİzmir\n");
$ham = file('sehirler.txt');
var_dump($ham[0]);
/*
string(7) "Ankara
"
*/
echo count($ham), "\n"; // çıktı: 4
$temiz = file('sehirler.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
print_r($temiz);
/*
Array
(
[0] => Ankara
[1] => Bursa
[2] => İzmir
)
*/İlk elemanın uzunluğunun 7 olması satır sonunun string'in içinde kaldığını gösterir. Bayraksız okumada dört eleman vardır çünkü boş satır da bir elemandır. Bayraklarla okunduğunda hem satır sonları hem boş satır temizlenir. Dönen diziyi işlemek için array_map ve array_filter gibi dizi fonksiyonlarından yararlanabilirsiniz.
Akışla çalışmak: fopen, fgets, fwrite, fclose

file_get_contents() ve file() dosyanın tamamını belleğe alır. Birkaç yüz megabaytlık bir günlük dosyasını bu şekilde okumak bellek sınırına takılabilir; böyle bir hata alıyorsanız memory_limit hatası yazısına bakabilirsiniz. Daha iyi çözüm dosyayı fopen() ile açıp satır satır okumaktır. fopen() başarıda bir dosya işaretçisi (resource), başarısızlıkta false döndürür ve bir E_WARNING üretir.
<?php
file_put_contents('buyuk.txt', "satır 1\nsatır 2\nsatır 3\n");
$fp = fopen('buyuk.txt', 'r');
if ($fp === false) {
exit("Dosya açılamadı\n");
}
$no = 0;
while (($satir = fgets($fp)) !== false) {
$no++;
echo $no, ': ', rtrim($satir, "\n"), "\n";
}
if (!feof($fp)) {
echo "Okuma yarıda kesildi\n";
}
fclose($fp);
/*
1: satır 1
2: satır 2
3: satır 3
*/fgets() her çağrıda bir satır döndürür ve satır sonunu da dahil eder; okunacak veri kalmadığında false döner. Döngü koşulunu !== false ile yazmak önemlidir: İçinde yalnızca "0" bulunan bir satır gevşek kontrolde döngüyü erken bitirir. Döngüden sonra feof() ile dosya sonuna gerçekten ulaşılıp ulaşılmadığını kontrol etmek, kılavuzdaki örnekte de önerilen bir yöntemdir; feof() dosya sonunda ya da bir hata oluştuğunda true döner. İsteğe bağlı length parametresi verilirse okuma length - 1 bayta, satır sonuna veya dosya sonuna ulaşıldığında (hangisi önce gelirse) durur.
Satır satır okumayı bir fonksiyonun içine alıp her satırı yield ile döndürmek, büyük dosyaları foreach ile rahatça gezmenin yaygın bir yoludur. Bu kalıp generator ve yield yazısında anlatılıyor.
fopen kipleri (mode)
fopen() fonksiyonunun ikinci parametresi dosyanın hangi amaçla açılacağını belirler. En çok kullanılan kipler aşağıdaki tabloda özetlenmiştir. Kılavuzdaki tam liste e ve n gibi yalnızca POSIX sistemlerde geçerli ek bayrakları da içerir.
| Kip | Okuma/Yazma | Dosya yoksa | Dosya varsa | İşaretçi |
|---|---|---|---|---|
| r | yalnız okuma | hata (false) | olduğu gibi | başta |
| r+ | okuma ve yazma | hata (false) | olduğu gibi | başta |
| w | yalnız yazma | oluşturur | içeriği sıfırlar | başta |
| a | yalnız yazma | oluşturur | korur, sona ekler | sonda |
| x | yalnız yazma | oluşturur | hata (false) | başta |
| c | yalnız yazma | oluşturur | korur, sıfırlamaz | başta |
x kipi "yalnızca yoksa oluştur" anlamına gelir. Dosya zaten varsa çağrı false döner ve uyarı üretir; bu, iki işlemin aynı dosyayı aynı anda yaratmaya çalıştığı durumlarda işe yarar.
<?php
$fp = fopen('alfabe.txt', 'x');
var_dump($fp);
/*
Warning: fopen(alfabe.txt): Failed to open stream: File exists in /yol/ornek.php on line 2
bool(false)
*/Kılavuz, işletim sistemlerinin farklı satır sonu kullandığını da hatırlatır: Unix tabanlı sistemler \n, Windows \r\n kullanır. Windows'ta kipin sonuna eklenen t metin çevirisi yapar, b ise ikili kipi zorlar. Varsayılan b kipidir ve kılavuz taşınabilirlik için t kipine dayanmamanızı önerir. Windows yollarında ters eğik çizgiyi kaçırmanız ("c:\\klasor\\dosya.txt") ya da düz eğik çizgi kullanmanız gerekir.
Kilitli okuma-değiştirme-yazma: küçük bir sayaç örneği
Bir dosyadaki değeri okuyup değiştirip geri yazmak, en çok yarış durumu (race condition) yaşanan işlemdir. İki istek aynı anda eski değeri okursa biri diğerinin yazdığını ezer. Kılavuz bu senaryo için c kipini önerir: Dosya varsa sıfırlanmadan açılır, böylece önce kilit alınıp sonra kesme yapılabilir. w kipi kilit alınmadan önce dosyayı sıfırlayacağı için bu iş için uygun değildir.
<?php
function sayaciArtir(string $dosya): int
{
$fp = fopen($dosya, 'c+');
if ($fp === false) {
throw new RuntimeException("$dosya açılamadı");
}
try {
if (!flock($fp, LOCK_EX)) {
throw new RuntimeException('Kilit alınamadı');
}
$deger = (int) stream_get_contents($fp);
$deger++;
ftruncate($fp, 0);
rewind($fp);
fwrite($fp, (string) $deger);
fflush($fp);
flock($fp, LOCK_UN);
return $deger;
} finally {
fclose($fp);
}
}
echo sayaciArtir('sayac.txt'), "\n"; // çıktı: 1
echo sayaciArtir('sayac.txt'), "\n"; // çıktı: 2
echo sayaciArtir('sayac.txt'), "\n"; // çıktı: 3Akış şöyledir: c+ ile dosya okuma ve yazma için açılır, flock(..., LOCK_EX) başka bir işlem kilidi bırakana kadar bekler, mevcut değer stream_get_contents() ile okunur, ftruncate() ile dosya boşaltılır, rewind() işaretçiyi başa alır ve yeni değer yazılır. fflush() tamponu kilit bırakılmadan önce diske gönderir; kılavuzdaki flock() örneği de aynı sırayı izler. finally bloğu, araya bir istisna girse bile dosyanın kapanmasını sağlar. Kilidin fclose() çağrıldığında da serbest kaldığını kılavuz ayrıca belirtir.
Beklemek istemiyorsanız LOCK_EX | LOCK_NB verebilirsiniz; bu durumda kilit hemen alınamazsa flock() beklemeden false döner. Kılavuz iki önemli sınır daha belirtir: flock() FAT gibi eski dosya sistemlerinde desteklenmez ve her zaman false döner; çok iş parçacıklı (multithreaded) sunucu ortamlarında da bazı işletim sistemlerinde süreç düzeyinde çalıştığı için aynı süreçteki iş parçacıklarını korumayabilir.
CSV okuma ve yazma: fgetcsv ve fputcsv
fputcsv() bir diziyi CSV satırı olarak biçimlendirip akışa yazar, fgetcsv() de bir satırı okuyup alanlara ayırır. İçinde virgül ya da çift tırnak bulunan alanları doğru şekilde tırnak içine alır ve tırnakları ikiler. PHP 8.4 ile birlikte iki fonksiyonda da escape parametresinin varsayılan değerine güvenmek kullanımdan kaldırıldı (deprecated); parametreyi açıkça vermeniz gerekir. Kılavuz, RFC 4180 ile uyumlu CSV için escape değerini boş string '' yapmanızı önerir ve varsayılanın en erken PHP 9.0'da değişeceğini not eder.
<?php
$satirlar = [
['ad', 'şehir', 'not'],
['Ayşe', 'İzmir', 'Dedi ki "merhaba"'],
['Mehmet', 'Ankara', 'virgül, içeren alan'],
];
$fp = fopen('kisiler.csv', 'w');
foreach ($satirlar as $alanlar) {
fputcsv($fp, $alanlar, ',', '"', '');
}
fclose($fp);
echo file_get_contents('kisiler.csv');
/*
ad,şehir,not
Ayşe,İzmir,"Dedi ki ""merhaba"""
Mehmet,Ankara,"virgül, içeren alan"
*/
$fp = fopen('kisiler.csv', 'r');
$baslik = fgetcsv($fp, null, ',', '"', '');
while (($alanlar = fgetcsv($fp, null, ',', '"', '')) !== false) {
$kayit = array_combine($baslik, $alanlar);
echo $kayit['ad'], ' / ', $kayit['not'], "\n";
}
fclose($fp);
/*
Ayşe / Dedi ki "merhaba"
Mehmet / virgül, içeren alan
*/İlk satırı başlık olarak okuyup array_combine() ile her kaydı ilişkisel diziye çevirmek, sütunlara adıyla erişmenin pratik bir yoludur. Ayırıcıyı noktalı virgül yapmak isterseniz ikinci parametreyi ';' olarak verirsiniz; ayırıcı ve tırnak karakterinin tek baytlık olması gerekir, aksi hâlde ValueError fırlatılır. Kılavuz ayrıca CSV dosyasındaki boş bir satırın hata sayılmadığını, tek bir null alan içeren dizi olarak döndüğünü belirtir; döngünüzde bu durumu atlamanız gerekebilir. escape parametresini vermezseniz PHP 8.5.12 aşağıdaki uyarıyı üretir:
<?php
$fp = fopen('kisiler.csv', 'r');
$alanlar = fgetcsv($fp);
fclose($fp);
/*
Deprecated: fgetcsv(): the $escape parameter must be provided as its default value will change in /yol/ornek.php on line 3
*/PHP 8.4'te kullanımdan kaldırılan diğer davranışlar ve nasıl düzeltilecekleri PHP 8.4 deprecated uyarıları yazısında toplanmıştır.
Dosya var mı, okunabilir mi, silme
Okumadan önce dosyanın varlığını file_exists(), okunabilirliğini is_readable(), boyutunu bayt olarak filesize() ile öğrenebilirsiniz. Silmek için unlink() kullanılır. file_exists() dosya ve dizin için true döner, var olmayan bir dosyayı gösteren sembolik bağlantı için ise false döner. Kılavuza göre yerel dosyalarda bu sonuç önbelleğe alınmaz, diğer sarmalayıcılarla (wrapper) kullanılan yollarda alınır; ayrıntı için clearstatcache() sayfasına bakılabilir.
<?php
var_dump(file_exists('notlar.txt')); // çıktı: bool(true)
var_dump(is_readable('notlar.txt')); // çıktı: bool(true)
var_dump(filesize('notlar.txt')); // çıktı: int(14)
var_dump(unlink('notlar.txt')); // çıktı: bool(true)
var_dump(file_exists('notlar.txt')); // çıktı: bool(false)Önce kontrol edip sonra açmak tek başına güvenli bir yöntem değildir; kontrol ile açma arasında dosya silinebilir veya değişebilir. Bu yüzden asıl güvence, açma ya da okuma fonksiyonunun dönüş değerini kontrol etmektir. Varlık kontrolü kullanıcıya anlamlı bir mesaj vermek için yararlıdır.
Göreli yollar ve çalışma dizini
'notlar.txt' gibi göreli bir yol, betiğin bulunduğu klasöre göre değil, işlemin o anki çalışma dizinine göre çözülür. Kılavuzun komut satırı bölümü, CLI SAPI'nin çalışma dizinini betiğin dizinine değiştirmediğini açıkça belirtir. Yani php araclar/rapor.php komutunu proje kökünden çalıştırırsanız dosyalar proje kökünde aranır. Betiğin yanındaki dosyaya kesin olarak ulaşmak için sihirli sabit __DIR__ ile mutlak yol kurun: file_get_contents(__DIR__ . '/veri.txt'). Sihirli sabitler PHP sabitleri yazısında, komut satırı kullanımı PHP CLI yazısında anlatılıyor.
Sık yapılan hatalar

- Dönüş değerini
if (!$veri)ile kontrol etmek. Boş dosya ve0bayt yazımı da hata gibi görünür;=== falsekullanın. file()ile okunan satırları satır sonunu atmadan karşılaştırmak.FILE_IGNORE_NEW_LINESverin ya dartrim()uygulayın.- Büyük dosyaları
file_get_contents()ile okumak. Satır satır işlenebilecek veriyifopen()vefgets()ile okuyun. - Okuma-değiştirme-yazma işleminde
wkipini kullanmak. Dosya kilit alınmadan sıfırlanır;cveyac+kullanın. fgetcsv()vefputcsv()çağrılarındaescapeparametresini vermemek. PHP 8.4 ve sonrasında Deprecated uyarısı alırsınız.- Göreli yolların betiğin klasörüne göre çözüleceğini varsaymak.
__DIR__ile mutlak yol kurun. - Kullanıcıdan gelen dosya adını doğrudan
fopen()veyafile_get_contents()fonksiyonuna vermek. Bu fonksiyonlarhttp://gibi URL'leri de kabul edebildiği için dosya adını kendi belirlediğiniz bir klasör ve izin verilen adlarla sınırlayın.
Son madde için önemli bir ayrıntı: Kılavuza göre fopen(), "scheme://..." biçimindeki bir adı URL olarak yorumlar ve kayıtlı bir sarmalayıcı arar; ağ sarmalayıcıları için allow_url_fopen ayarının açık olması gerekir. Kullanıcı girdisini doğrulama yöntemleri filter_var ile veri doğrulama yazısında ele alınıyor. Formdan dosya yükleme sınırları ise sunucu ayarıdır ve upload_max_filesize yazısında anlatılıyor.
Hangi fonksiyonu ne zaman kullanmalı?
| İhtiyaç | Fonksiyon | Not |
|---|---|---|
| Küçük dosyayı string olarak okumak | file_get_contents | Hata durumunda false ve E_WARNING |
| Dosyaya tek seferde yazmak | file_put_contents | Yazılan bayt sayısını döndürür |
| Sona eklemek | file_put_contents + FILE_APPEND | LOCK_EX ile birlikte kullanılabilir |
| Satırları dizi olarak almak | file | FILE_IGNORE_NEW_LINES, FILE_SKIP_EMPTY_LINES |
| Büyük dosyayı satır satır okumak | fopen + fgets | Bellekte bir satır tutulur |
| CSV okumak ve yazmak | fgetcsv, fputcsv | escape parametresini açıkça verin |
| Eşzamanlı güncelleme | fopen(c+) + flock | Kilit advisory türdendir |
JSON biçimindeki ayar ya da veri dosyaları için okuma ve yazmayı json_decode() ve json_encode() ile birleştirebilirsiniz; ayrıntılar json_encode ve json_decode yazısında. Yapılandırılmış ve sorgulanabilir veri için dosya yerine veritabanı daha uygun olabilir; PHP'den SQLite ile çalışmak PDO veritabanı bağlantısı yazısında anlatılıyor.
Sık Sorulan Sorular
file_get_contents ile fopen arasındaki fark nedir?
file_get_contents() dosyanın tamamını tek çağrıda string olarak döndürür ve dosyayı kendisi açıp kapatır. fopen() ise bir akış açar; okuma ve yazmayı parça parça yapmanıza, kilit almanıza ve işaretçiyi konumlandırmanıza izin verir. Küçük dosyalar için ilki, büyük dosyalar ve kilitli işlemler için ikincisi uygundur.
file_put_contents dosyanın üzerine mi yazar, sonuna mı ekler?
Varsayılan olarak üzerine yazar. Dosya yoksa oluşturur. Sona eklemek için üçüncü parametreye FILE_APPEND verin; eşzamanlı yazımlar için FILE_APPEND | LOCK_EX kullanabilirsiniz.
"Failed to open stream: No such file or directory" uyarısı neden çıkar?
Dosya verilen yolda yoktur ya da göreli yol beklediğiniz dizine göre çözülmemiştir. CLI'de çalışma dizini betiğin klasörü değildir. __DIR__ ile mutlak yol kurun ve dönüş değerini === false ile kontrol edin.
Türkçe karakterli dosya içeriği bozulur mu?
Hayır. Bu fonksiyonlar binary-safe olduğu için baytları değiştirmeden okur ve yazar. Dosya UTF-8 ise içerik de UTF-8 olarak gelir. Yalnızca uzunluk ve kesme gibi işlemlerde bayt ile karakter farkını hesaba katmanız gerekir.
flock her ortamda çalışır mı?
Hayır. Kılavuza göre FAT gibi eski dosya sistemlerinde her zaman false döner, kilit advisory türdendir ve bazı çok iş parçacıklı sunucu ortamlarında aynı süreçteki iş parçacıklarını korumayabilir. Dönüş değerini mutlaka kontrol edin.
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 json_encode ve json_decode · PHP generator ve yield · PHP CLI kullanımı · PHP hata seviyeleri