PHP'de bir metni belirli bir kalıba göre biçimlendirmek için sprintf() kullanılır: biçim metnindeki %s, %d, %.2f gibi yer tutucular sırayla verdiğiniz değerlerle doldurulur ve sonuç metin olarak döner. printf() aynı işi yapıp sonucu doğrudan ekrana yazar. Sayıları Türkçe biçimde, yani binlik ayırıcı nokta ve ondalık ayırıcı virgül olacak şekilde yazmak için ise number_format($sayi, 2, ',', '.') kullanılır.
Bu yazıda printf ailesinin biçim belirtici sözdizimini parça parça açıyor, genişlik ve doldurma karakterlerini, ondalık hassasiyetini, argüman numaralandırmayı, PHP 8 ile değişen hata davranışını ve Türkçe harflerle sütun hizalamanın tuzağını gösteriyoruz. Ardından number_format() ve intl eklentisindeki NumberFormatter ile para ve sayı biçimlendirmeye geçiyoruz. Metin işlemenin temelleri için PHP string fonksiyonları yazısına bakabilirsiniz.
printf ailesi: hangisi ne döndürür?

Aynı biçim sözdizimini kullanan beş fonksiyon vardır ve aralarındaki fark, sonucu nereye gönderdikleri ile argümanları nasıl aldıklarıdır. sprintf() biçimlenmiş metni döndürür. printf() metni çıktıya yazar ve yazdığı metnin uzunluğunu döndürür. fprintf() metni bir dosya akışına yazar. vsprintf() ve vprintf() ise değerleri ayrı argümanlar yerine tek bir dizi olarak alır; değerleri bir veritabanı satırından veya yapılandırmadan aldığınızda işe yarar.
| Fonksiyon | Değerleri nasıl alır | Sonuç |
|---|---|---|
| sprintf | ayrı argümanlar | metni döndürür |
| printf | ayrı argümanlar | çıktıya yazar, uzunluğu döndürür |
| fprintf | akış + ayrı argümanlar | akışa yazar, uzunluğu döndürür |
| vsprintf | tek dizi | metni döndürür |
| vprintf | tek dizi | çıktıya yazar, uzunluğu döndürür |
<?php
$mesaj = sprintf('%s için %d ürün hazır', 'Ayşe', 3);
echo $mesaj, "\n"; // çıktı: Ayşe için 3 ürün hazır
$uzunluk = printf("%s\n", 'merhaba'); // çıktı: merhaba
echo $uzunluk, "\n"; // çıktı: 8 (yeni satır dahil)
echo vsprintf('%s, %s ve %s', ['Ece', 'Mert', 'Sena']), "\n"; // çıktı: Ece, Mert ve Sena
fprintf(STDOUT, "Kalan: %d\n", 12); // çıktı: Kalan: 12Biçim belirticinin yapısı
Biçim metnindeki her yer tutucu % ile başlar ve kılavuzdaki şu kalıbı izler: %[argnum$][bayraklar][genişlik][.hassasiyet]belirtici. Köşeli parantez içindekiler isteğe bağlıdır; zorunlu olan yalnızca sondaki belirtici harfidir. Argüman numarası hangi değerin kullanılacağını, bayraklar hizalama ve dolguyu, genişlik en az kaç karakter yer kaplanacağını, hassasiyet ise ondalık basamak sayısını veya metnin en fazla uzunluğunu belirler. Biçim metninde düz bir yüzde işareti yazmak için %% kullanırsınız.
| Belirtici | Değeri nasıl yorumlar | Örnek çıktı |
|---|---|---|
| %s | metin | ab |
| %d | işaretli tam sayı | +5 (bayrakla) |
| %u | işaretsiz tam sayı | 5 |
| %f | ondalık sayı, yerel ayara duyarlı | 3,50 veya 3.50 |
| %F | ondalık sayı, yerel ayardan bağımsız | 3.50 |
| %e, %E | bilimsel gösterim | 1.234500e+3 |
| %g, %G | f veya e biçiminden uygun olanı | 1234.5 |
| %x, %X | onaltılık, küçük veya büyük harf | ff, FF |
| %o | sekizlik | 10 |
| %b | ikilik | 101 |
| %c | ASCII koduna karşılık gelen karakter | A |
| %% | düz yüzde işareti | % |
<?php
echo sprintf('%5.1f|%-6s|%06.2f|%+d', 3.14159, 'ab', 3.14159, 5), "\n";
// çıktı: 3.1|ab |003.14|+5
echo sprintf('%x %X %o %b', 255, 255, 8, 5), "\n"; // çıktı: ff FF 10 101
echo sprintf('%e', 1234.5), "\n"; // çıktı: 1.234500e+3
echo sprintf('%c%c', 80, 72), "\n"; // çıktı: PH
echo sprintf('İndirim: %%%d', 15), "\n"; // çıktı: İndirim: %15
echo sprintf('%u', -1), "\n"; // çıktı: 18446744073709551615
echo sprintf('[%5c]', 65), "\n"; // çıktı: [A]Değerler belirticiye uygun tipe zorlanır. Kılavuzdaki tabloya göre s metne, d, u, c, o, x, X, b tam sayıya, e, f, g ve büyük harfli karşılıkları ondalık sayıya çevrilir. Bu yüzden sprintf('%d', 3.99) sonucu yuvarlanmış 4 değil, ondalığı atılmış 3 olur; sprintf('%d', '12abc') ise metnin başındaki sayıyı alıp 12 yazar. Bu zorlamalar sessizce olur, yani hatalı veriyi gizleyebilir.
Örneğin son iki satırı da açıklayalım. %u değeri işaretsiz tam sayı olarak yazar; negatif bir sayı verdiğinizde eksi işareti görünmez, onun yerine sayının bellekteki bit dizisi işaretsiz olarak okunur. 64 bitlik PHP'de -1 bu yüzden çok büyük bir sayı olarak çıkar. Kılavuz ayrıca %c belirticisinin dolgu ve genişliği yok saydığını belirtir; [%5c] yazsanız bile çıktıya yalnızca tek karakter eklenir. Negatif olabilecek değerler için %d, işareti her zaman göstermek için %+d kullanın.
Genişlik, hizalama ve dolgu karakteri
Genişlik, sonucun en az kaç karakter olacağını söyler; değer daha uzunsa kesilmez. Varsayılan hizalama sağa yaslıdır ve boşlukla doldurulur. - bayrağı sola yaslar. 0 bayrağı sayıları soldan sıfırla doldurur; tarih ve fatura numarası üretirken çok kullanılır. Boşluk veya sıfır dışında bir karakterle doldurmak için kesme işaretinden sonra o karakteri yazarsınız: %'*8s yıldızla, %'.10d noktayla doldurur. Genişlik yerine * yazarsanız genişlik değeri, biçimlenecek değerden hemen önceki argümandan alınır.
<?php
echo sprintf("[%5d] [%-5d] [%05d]", 42, 42, 42), "\n"; // çıktı: [ 42] [42 ] [00042]
echo sprintf("[%'*8s] [%'.10d] [%-'x10s]", 'abc', 42, 'sol'), "\n";
// çıktı: [*****abc] [........42] [solxxxxxxx]
echo sprintf('%04d-%02d-%02d', 2026, 11, 7), "\n"; // çıktı: 2026-11-07
echo sprintf('FTR-%06d', 381), "\n"; // çıktı: FTR-000381
echo sprintf('[%*d]', 6, 42), "\n"; // çıktı: [ 42]Hassasiyet: ondalık basamak ve metin kesme

Noktadan sonra yazılan sayının anlamı belirticiye göre değişir. f, F, e ve E için ondalık basamak sayısıdır ve verilmezse 6 kullanılır; bu yüzden sprintf('%f', 1.5) sonucu 1.500000 olur. g ailesinde anlamlı basamak sayısını, s belirticisinde ise metnin en fazla uzunluğunu belirtir. Nokta yazıp sayı yazmazsanız hassasiyet 0 kabul edilir. Kılavuzdaki sürüm notuna göre PHP 8.5'te, hassasiyeti belirtilmemiş biçimlendiricilerin hassasiyeti sıfırlaması hatası düzeltildi.
Ondalık yuvarlamada dikkat edilmesi gereken bir nokta var: %.2f ondalık sayının bellekteki ikili gösterimini yuvarlar. 1.005 gibi bir değer ikili sistemde tam olarak temsil edilemez ve aslında 1.00499... olarak saklandığı için sprintf('%.2f', 1.005) sonucu 1.00 olur. Aynı değer number_format() ile 1.01 çıkar; bu fonksiyon kılavuza göre "yarımı yukarı yuvarla" kuralını uygular. Para hesaplarında sonucun hangi fonksiyonla yuvarlandığını bilmek bu yüzden önemlidir.
<?php
echo sprintf('%f', 1.5), "\n"; // çıktı: 1.500000
echo sprintf('%.2f', 2 / 3), "\n"; // çıktı: 0.67
echo sprintf('%.2f', 1.005), "\n"; // çıktı: 1.00
echo number_format(1.005, 2), "\n"; // çıktı: 1.01
echo sprintf('%.3s', 'Kalem'), "\n"; // çıktı: KalArgüman numaralandırma: %1$s ve %2$d
Varsayılan olarak yer tutucular argümanları sırayla tüketir. Kılavuzun anlattığı tipik sorun, biçim metni çeviri dosyasından geldiğinde ortaya çıkar: Türkçe cümlede özne ve sayının sırası İngilizce cümleden farklı olabilir, ama kodda argüman sırası sabittir. Bu durumda yer tutucuya %2$s gibi bir konum numarası eklersiniz; numara, yüzde işaretinden hemen sonra ve diğer bütün bayraklardan önce gelmelidir. Aynı argümanı birden çok kez kullanmak da bu yolla mümkündür. Biçim metnini çift tırnak içinde yazarsanız $ işaretinin değişken sanılmaması için tek tırnak kullanmak daha güvenlidir.
<?php
$adet = 5;
$yer = 'depo';
echo sprintf('There are %1$d boxes in the %2$s', $adet, $yer), "\n";
// çıktı: There are 5 boxes in the depo
echo sprintf('%2$s içinde %1$d kutu var', $adet, $yer), "\n";
// çıktı: depo içinde 5 kutu var
echo sprintf('%2$s: %1$03d. %2$s kapasitesi dolmak üzere', $adet, $yer), "\n";
// çıktı: depo: 005. depo kapasitesi dolmak üzerePHP 8 ile değişen hata davranışı
PHP 8.0'dan önce eksik argüman verilen bir sprintf() çağrısı false döndürür ve yalnızca bir uyarı verirdi; bu false değeri metne çevrilince boş metin olur ve hata sessizce kaybolurdu. PHP 8.0'dan beri fonksiyon hiç false döndürmez. Gerekenden az argüman verirseniz ArgumentCountError, negatif veya aşırı büyük genişlik ya da hassasiyet verirseniz ValueError fırlatılır. Bu istisnaları yakalamak ve hata türlerinin ayrıntıları için TypeError ve ArgumentCountError hataları yazısına bakabilirsiniz.
<?php
try {
echo sprintf('%s adlı müşterinin %d siparişi var', 'Ece');
} catch (ArgumentCountError $e) {
echo get_class($e), ': ', $e->getMessage(), "\n";
}
// çıktı: ArgumentCountError: 3 arguments are required, 2 givenMesajdaki sayılar ilk bakışta kafa karıştırabilir: biçim metni de bir argüman sayıldığı için iki yer tutuculu bir biçim üç argüman ister.
Türkçe harflerle sütun hizalama tuzağı
Kılavuz, genişlik belirticisinin bir karakteri birden fazla baytla yazılan kodlamalarda beklenmedik sonuç verebileceği konusunda uyarır. Neden basit: printf ailesi genişliği bayt olarak sayar. Kadıköy yedi harf ama dokuz bayttır; %-10s ile hizalandığında üç yerine yalnızca bir boşluk alır ve sütunlar kayar. Aynı nedenle %.4s gibi bir hassasiyet Türkçe harfi ortasından kesebilir. Çözüm, metin sütunlarını mb_str_pad() (PHP 8.3 ve üstü) ile doldurup printf()'e yalnızca sayı sütunlarının biçimlendirilmesini bırakmaktır.
<?php
$satirlar = [['Kadıköy', 12], ['Bostancı', 7], ['Moda', 30]];
foreach ($satirlar as [$semt, $adet]) {
printf("%-10s|%3d\n", $semt, $adet);
}
/* çıktı:
Kadıköy | 12
Bostancı | 7
Moda | 30
*/
foreach ($satirlar as [$semt, $adet]) {
printf("%s|%3d\n", mb_str_pad($semt, 10), $adet);
}
/* çıktı:
Kadıköy | 12
Bostancı | 7
Moda | 30
*/number_format(): Türkçe binlik ve ondalık ayırıcı
number_format() bir sayıyı binlik gruplara ayırarak metne çevirir. İlk parametre sayı, ikincisi ondalık basamak sayısı, üçüncüsü ondalık ayırıcı, dördüncüsü binlik ayırıcıdır. Varsayılan İngilizce biçimdir: ondalık ayırıcı nokta, binlik ayırıcı virgüldür ve ondalık basamak sayısı 0'dır. Türkçe biçim için ayırıcıları yer değiştirirsiniz. PHP 8.0'dan önce fonksiyon bir, iki veya dört parametreyle çağrılabiliyordu, üç parametre kabul edilmiyordu; bu kısıt 8.0 ile kalktı. PHP 8.3'ten beri ikinci parametreye negatif bir sayı verirseniz sayı ondalık noktanın solundaki basamaklara yuvarlanır.
<?php
$tutar = 1234567.891;
echo number_format($tutar), "\n"; // çıktı: 1,234,568
echo number_format($tutar, 2), "\n"; // çıktı: 1,234,567.89
echo number_format($tutar, 2, ',', '.'), "\n"; // çıktı: 1.234.567,89
echo number_format($tutar, 0, ',', '.'), "\n"; // çıktı: 1.234.568
echo number_format(1234.5, 2, ',', ''), "\n"; // çıktı: 1234,50
echo number_format(1234567, -3, ',', '.'), "\n"; // çıktı: 1.235.000
echo number_format(2.5), ' ', number_format(-0.01), "\n"; // çıktı: 3 0Son satır iki ayrıntıyı gösteriyor: 2.5 yarımı yukarı yuvarlama kuralıyla 3 olur ve kılavuzdaki 7.2 sürüm notuna göre fonksiyon artık -0 döndürmez. number_format() her zaman metin döndürür. Biçimlenmiş değeri hesaba sokmak sık yapılan bir hatadır: '1.234,56' metni PHP için geçerli bir sayı değildir, baştaki 1.234 kısmı sayı olarak okunur ve bir uyarı verilir. Hesabı sayılarla yapın, biçimlendirmeyi yalnızca ekrana yazarken uygulayın.
<?php
$goster = number_format(1234.56, 2, ',', '.');
var_dump($goster + 1);
/* çıktı:
Warning: A non-numeric value encountered in /yol/ornek.php on line 3
float(2.234)
*/NumberFormatter: yerel ayara göre para ve yüzde
Uluslararası bir uygulamada her dil için ayırıcıları elle yazmak yerine intl eklentisindeki NumberFormatter sınıfını kullanabilirsiniz. Sınıf bir yerel ayar (tr_TR gibi) ve bir stil alır; ICU kütüphanesinin o dil için tanımladığı kurallarla biçimlendirir. DECIMAL stili sayıları, PERCENT stili yüzdeleri, CURRENCY stili ise formatCurrency() metoduyla para tutarlarını biçimlendirir; para birimi üç harfli ISO 4217 koduyla verilir. Kılavuza göre PHP 8.4'ten beri geçersiz bir yerel ayar adı ValueError fırlatır. Para biriminin simgesinin nereye yazılacağı gibi ayrıntılar ICU verisine bağlıdır, bu yüzden çıktıyı kendi ortamınızda doğrulayın.
<?php
$sayi = new NumberFormatter('tr_TR', NumberFormatter::DECIMAL);
$yuzde = new NumberFormatter('tr_TR', NumberFormatter::PERCENT);
$para = new NumberFormatter('tr_TR', NumberFormatter::CURRENCY);
echo $sayi->format(1234567.891), "\n"; // çıktı: 1.234.567,891
echo $yuzde->format(0.256), "\n"; // çıktı: %26
echo $para->formatCurrency(1234567.891, 'TRY'), "\n"; // çıktı: ₺1.234.567,89
echo $para->formatCurrency(49.9, 'EUR'), "\n"; // çıktı: €49,90Uygulamalı örnek: düz metin fatura özeti
Şimdi öğrendiklerimizi bir araya getirelim. E-posta veya terminal çıktısı için sabit genişlikli bir fatura özeti hazırlayacağız. Ürün adları Türkçe harf içerdiği için metin sütununu mb_str_pad() ile dolduruyoruz. Tutarları önce sayı olarak hesaplıyor, yalnızca yazdırırken number_format() ile Türkçe biçime çeviriyoruz; sonra bu metni %12s ile sağa yaslıyoruz. Biçimlenmiş tutar yalnızca rakam, nokta ve virgül içerdiği için bayt ve karakter sayısı aynıdır, bu yüzden burada printf() genişliği güvenle kullanılabilir. Fatura numarasını sıfırla doldurmak için de %06d kullanıyoruz.
<?php
$kalemler = [['Çay bardağı', 6, 42.5], ['Şeker kutusu', 1, 189.9], ['Kaşık', 12, 15]];
$tl = fn(float $x): string => number_format($x, 2, ',', '.');
printf("Fatura No: %06d\n", 381);
$toplam = 0;
foreach ($kalemler as [$urun, $adet, $birim]) {
$tutar = $adet * $birim;
$toplam += $tutar;
printf("%s %3d x %8s %12s\n", mb_str_pad($urun, 14), $adet, $tl($birim), $tl($tutar));
}
printf("%s %12s\n", mb_str_pad('TOPLAM', 29), $tl($toplam));
/* çıktı:
Fatura No: 000381
Çay bardağı 6 x 42,50 255,00
Şeker kutusu 1 x 189,90 189,90
Kaşık 12 x 15,00 180,00
TOPLAM 624,90
*/Çıktıda bütün sütunların hizalı olduğuna dikkat edin. Aynı satırı %-14s ile yazsaydınız Türkçe harf sayısı farklı olan satırlar birbirinden kayardı. Toplamı $toplam değişkeninde sayı olarak tuttuğumuz için ek bir dönüştürme gerekmedi.
%f ve yerel ayar
Belirtici tablosunda %f yerel ayara duyarlı, %F ise duyarsız olarak tanımlanır. setlocale(LC_NUMERIC, ...) ile Türkçe bir yerel ayar seçildiğinde %f ondalık ayırıcı olarak virgül kullanır. Ancak hangi yerel ayar adlarının bulunduğu işletim sistemine bağlıdır ve kılavuz, yerel ayar bilgisinin iş parçacığı (thread) başına değil süreç başına tutulduğunu, çok iş parçacıklı sunucu ortamlarında beklenmedik değişikliklere yol açabileceğini belirtir. Makineler arasında aynı sonucu almak istiyorsanız JSON, CSV veya API çıktısında %F kullanın, kullanıcıya gösterilen sayılar için number_format() veya NumberFormatter tercih edin.
<?php
// Türkçe yerel ayar sistemde varsa:
setlocale(LC_NUMERIC, 'tr_TR.UTF-8', 'tr_TR', 'Turkish');
printf("%.2f %.2F\n", 3.5, 3.5); // çıktı: 3,50 3.50
setlocale(LC_NUMERIC, 'C');Sık yapılan hatalar

printf()sonucunu bir değişkene atayıp metin beklemek:printf()uzunluk döndürür; metin içinsprintf()kullanın.%dile ondalık sayı yazdırmak: ondalık kısım yuvarlanmaz, atılır. Fiyatlar için%.2fveyanumber_format()kullanın.- Çift tırnak içinde
%1$syazmak:$sbir değişken gibi yorumlanmaya çalışılır; biçim metnini tek tırnakla yazın. number_format()sonucuyla hesap yapmak: çıktı metindir ve Türkçe biçimde sayı olarak okunamaz.- Türkçe metinleri
%-10sile hizalamak: genişlik bayt cinsindendir;mb_str_pad()kullanın. - Kullanıcıdan gelen metni biçim metni olarak kullanmak:
sprintf($kullanici_metni)içinde%geçerse eksik argüman hatası alırsınız. Kullanıcı metnini her zaman değer olarak verin:sprintf('%s', $metin). HTML çıktısında ayrıca kaçırma gerekir; bkz. filter_var ve htmlspecialchars.
Sık Sorulan Sorular
sprintf() ile metin birleştirme arasında performans farkı var mı?
PHP 8.4 sürüm notlarına göre yalnızca %s ve %d belirticisi içeren sprintf() çağrıları derleme aşamasında eşdeğer metin yerleştirmeye dönüştürülür; bu da fonksiyon çağrısı ve biçim çözümleme maliyetini ortadan kaldırır. Diğer durumlarda okunabilirliği esas alın.
Komut satırı betiğinde hata mesajını nasıl ayrı yazarım?
fprintf() ilk parametre olarak bir akış alır. CLI ortamında hazır tanımlı STDERR sabitini verirseniz biçimlenmiş mesaj standart hata akışına gider ve normal çıktıyla karışmaz: fprintf(STDERR, "Hata: %s\n", $mesaj). Bu sabitler ve diğer CLI ayrıntıları PHP CLI kullanımı yazısında.
money_format() fonksiyonu neden çalışmıyor?
money_format() PHP 8.0 ile kaldırılan fonksiyonlar arasındadır. Eski kodda karşılaşırsanız para biçimlendirme için NumberFormatter::formatCurrency() veya basit durumlarda number_format() kullanın.
Sayıyı yazıyla (bin iki yüz gibi) yazdırabilir miyim?
NumberFormatter sınıfının SPELLOUT stili, sayıyı seçilen dilde yazıya çevirmek için kullanılır. Sonucun dil kuralları ICU verisine bağlıdır; fatura gibi resmî belgelerde kullanmadan önce çıktıyı kontrol edin.
Tarihi biçimlendirmek için sprintf() mi kullanmalıyım?
Elinizde ayrı yıl, ay ve gün sayıları varsa sprintf('%04d-%02d-%02d', ...) pratiktir. Gerçek tarih hesapları ve saat dilimi için ise DateTimeImmutable::format() daha doğrudur; ayrıntılar PHP DateTime yazısında.
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 string fonksiyonları · PHP mbstring ve Türkçe karakterler · TypeError ve ArgumentCountError · PHP DateTime