تعيد number_format($number, $decimals) العدد نصًا مع فاصل للآلاف وعدد ثابت من المنازل العشرية: تعيد number_format(1234567.891, 2) النص "1,234,567.89". ومع وسيط واحد تقرّب إلى عدد صحيح: number_format(1234567.891) تساوي "1,234,568".
المعاملات الأربعة
number_format(
float $num,
int $decimals = 0,
?string $decimal_separator = ".",
?string $thousands_separator = ","
): string
الوسيط الثالث هو المحرف بين الجزء الصحيح والمنازل العشرية، والرابع هو المحرف بين مجموعات الأرقام الثلاثية. ويمكن أن يكون أيٌّ منهما أي نص، بما فيه النص الفارغ أو محرف متعدد البايتات. عدّل الفواصل أدناه لترى كل أسلوب:
تستخدم بيانات الإعدادات المحلية (CLDR) مسافة ضيقة غير قابلة للكسر (U+202F) للفرنسية ومسافة غير قابلة للكسر (U+00A0) للروسية، فلا ينقسم العدد أبدًا على سطرين. وفي HTML، مرّر "\u{202F}" أو "\u{00A0}" فاصلًا بدل المسافة العادية.
تنسيق عدد دون فاصل الآلاف
مرّر '' وسيطًا رابعًا. تحصل على عدد عادي بعدد ثابت من المنازل العشرية، وهو الشكل الذي تتوقعه بوابات الدفع وملفات CSV المصدّرة وقيم <input type="number">:
في السطر الأخير، round() قبل التحويل مهمة: يُخزَّن 19.9 * 100 على شكل 1989.9999999999998، و(int) وحدها ستقتطعه إلى 1989.
كيف تقرّب number_format
تقرّب number_format() النصف بعيدًا عن الصفر، كما تفعل round()، فيصبح 0.5 العدد 1 ويصبح -2.5 العدد -3. وتصحح أيضًا الخطأ الثنائي الضئيل في قيم مثل 2.675، ولهذا قد تختلف عن sprintf('%.2f'):
لا يمكن تخزين 2.675 بدقة في النظام الثنائي؛ فالقيمة المخزنة أقل منها بقليل جدًا. تنسّق sprintf() تلك القيمة المخزنة فتحصل على 2.67، بينما تعاملها number_format() وround() على أنها 2.675 التي كتبتها. إذا احتجت إلى قاعدة تقريب محددة، فاستدعِ round() أو floor() أو ceil() بنفسك أولًا (راجع التقريب والرياضيات) ومرّر النتيجة إلى number_format().
تنسيق المال والعملات الأخرى
لا تعرف number_format() شيئًا عن العملات، لذا تضيف الرمز بنفسك. ضع إشارة السالب قبل الرمز، وتذكّر أن الين لا منازل عشرية له:
للمخرجات المراعية للإعدادات المحلية مع موضع الرمز الصحيح لكل بلد، يؤدي NumberFormatter من امتداد intl المهمة كلها:
$fmt = new NumberFormatter('de_DE', NumberFormatter::CURRENCY);
echo $fmt->formatCurrency(1234.5, 'EUR'); // 1.234,50 € (a no-break space before €)
يتطلب امتداد intl، وهو غير مثبّت في كل مكان، لذا تكون number_format() مع رمزك الخاص هي الخيار القابل للنقل.
النتيجة نص لا عدد
هذا أشهر خطأ مع number_format(): تنسيق قيمة ثم الحساب بها. "1,234.50" ليس نصًا رقميًا، لذا لا تقرأ PHP إلا 1 قبل الفاصلة:
<?php
echo number_format(1234.5, 2) + 1;
Warning: A non-numeric value encountered in /home/index.php on line 2
2
وتمرير مثل هذا النص مرة أخرى إلى number_format() أسوأ: يرمي TypeError: number_format(): Argument #1 ($num) must be of type int|float, string given. احتفظ بالعدد الخام للحساب ولا تنسّق إلا لحظة الطباعة. وإذا تلقيت نصًا منسقًا من نموذج أو ملف، فاحذف الفواصل أولًا:
للحشو أو المحاذاة أو إشارة الموجب قبل العدد، استخدم sprintf() بدلًا منها؛ فهي لا تضيف فواصل الآلاف، لكنها تتحكم في العرض والإشارة.
الأسئلة الشائعة
كيف أنسّق عددًا بفواصل في PHP؟
استدعِ number_format($n): تعيد number_format(1234567) النص "1,234,567". ومرّر وسيطًا ثانيًا للمنازل العشرية: تعيد number_format(1234567.891, 2) النص "1,234,567.89".
كيف أستخدم number_format دون فاصلة؟
مرّر نصًا فارغًا فاصلًا للآلاف: تعيد number_format(1234.5, 2, '.', '') النص "1234.50". وهذه الصيغة التي تتوقعها عادة واجهات الدفع البرمجية وملفات CSV.
هل تقرّب number_format أم تقتطع؟
تقرّب، والنصف بعيدًا عن الصفر: number_format(2.5) تساوي "3"، وnumber_format(-2.5) تساوي "-3"، وnumber_format(2.675, 2) تساوي "2.68". ولاقتطاع المنازل العشرية بدلًا من ذلك، استخدم floor() أولًا: تعطي number_format(floor(2.679 * 100) / 100, 2) النص "2.67".
كيف أنسّق الأعداد بالطريقة الأوروبية (1.234,56)؟
بدّل الفاصلين بالوسيطين الثالث والرابع: تعيد number_format(1234.56, 2, ',', '.') النص "1.234,56". وتستخدم الأساليب الفرنسية والسويسرية مسافة أو فاصلة عليا وسيطًا رابعًا.
لماذا تعطي number_format نتيجة خاطئة عندما أضيف إليها؟
تعيد number_format() نصًا مثل "1,234.50"، ولا تقرأ PHP إلا 1 قبل الفاصلة عندما تجري عليه عمليات حسابية. احتفظ بالعدد للحسابات واستدعِ number_format() فقط عندما تطبعه.