لماذا لم يعد استخدام round() كافيًا؟ نظرة على عام 2025
\n\nكل من كتب متجرًا إلكترونيًا، أو وحدة محاسبة، أو محلل أسعار عملات في PHP، واجه السؤال: "كيف أعرض الرقم 19.9999999999999 بشكل جميل كـ 20.00؟" هذا السؤال حصد آلاف المشاهدات على Stack Overflow، وليس من دون سبب. في عام 2025، حيث يصل PHP بفخر إلى الإصدار 8.4 وما فوق، قد تفاجئك الحيل القديمة مع round() بمفاجآت غير سارة.
لنحسم الأمر نهائيًا: كيف نعرض رقمًا بمنزلتين عشريتين في PHP بطريقة موثوقة وجميلة وتتوافق مع المعايير الحديثة. لن ننسخ إجابة من منتدى فقط، بل سنفهم لماذا تعمل كل طريقة بهذه الطريقة.
\n\nالمشكلة الأولى: الفاصلة العائمة — صديقك الخبيث
\n\nPHP، مثل معظم اللغات، تستخدم تنسيق IEEE 754 للأعداد ذات الفاصلة العائمة (float). هذا يعني أن 0.1 + 0.2 قد لا تساوي 0.3، بل 0.30000000000000004. و 19.95 مضروبًا في 100 قد يعطي 1994.9999999999998. إذا استخدمت round() مباشرة، ستحصل على نتيجة غير متوقعة.
لذلك، في عام 2025، القاعدة الأولى: لا تثق في float للمعاملات المالية. لكن إذا كنت تحتاج فقط إلى تنسيق المخرجات (مثل سعر على واجهة المتجر)، فالطرق التالية هي الحل الأمثل.
\n\nالطريقة الأولى: الكلاسيكية — number_format()
\n\nهذه هي الطريقة الأكثر شيوعًا وأمانًا لـ 99% من المهام. الدالة number_format() لا تقوم فقط بالتقريب، بل تقوم بتنسيق الرقم مع فواصل الآلاف وعدد محدد من المنازل العشرية.
<?php\n$price = 19.999999;\necho number_format($price, 2, '.', ''); // الناتج: 20.00\n\n$salary = 1234.5;\necho number_format($salary, 2, '.', ','); // الناتج: 1,234.50\n?>\n\nلماذا هذه الطريقة رائعة:
\n- \n
- تقوم بالتقريب تلقائيًا إلى العدد المحدد من المنازل (وفقًا للقواعد الرياضية). \n
- تسمح بتعيين فاصل الأعداد الصحيحة والعشرية الخاص بك. \n
- تضيف أصفارًا إذا كان الجزء العشري أقصر (مثل 5.00 بدلاً من 5). \n
نقطة دقيقة: إذا مررت نصًا، سيحاول PHP تحويله إلى رقم. كن حذرًا مع الإعدادات المحلية — فقد تُفسر الفاصلة في النص على أنها فاصل عشري.
\n\nمتى تستخدمها؟
\nلعرض الأسعار، والرواتب، والنسب المئوية، وأي بيانات تحتاج منزلتين عشريتين وفصل بين الخانات.
\n\nالطريقة الثانية: الدقة الرياضية — round()
\n\nالدالة round() ترجع رقمًا (من نوع float)، وليس نصًا. هذا مهم إذا كنت ستجري عمليات حسابية لاحقة.
<?php\n$value = 45.6789;\n$rounded = round($value, 2); // 45.68 (float)\n\n// لكن! إذا كنت تريد بالضبط منزلتين وصفر في النهاية:\necho $rounded; // سيطبع 45.68 (كل شيء بخير)\necho round(45.0, 2); // سيطبع 45 (float)، وليس 45.00\n?>\n\nالمأزق: round() تستخدم "التقريب المصرفي" (round half to even) افتراضيًا في PHP 8+. هذا يعني أن 2.5 ستُقرب إلى 2، و 3.5 إلى 4. للمعاملات المالية، قد يكون هذا غير مقبول. استخدم الثابت PHP_ROUND_HALF_UP للتقريب الكلاسيكي:
<?php\necho round(2.5, 0, PHP_ROUND_HALF_UP); // 3\necho round(2.5, 0); // 2 (تقريب مصرفي)\n?>\n\nالخلاصة: round() + number_format()
\nالثنائي المثالي: قم بالتقريب أولاً للحسابات، ثم قم بالتنسيق للعرض.
\n\n<?php\n$raw = 19.999999;\n$precise = round($raw, 2, PHP_ROUND_HALF_UP);\necho number_format($precise, 2, '.', ''); // 20.00\n?>\n\nالطريقة الثالثة: أناقة sprintf()
\n\nالدالة sprintf() هي أداة قوية لتنسيق النصوص. هل تقوم بالتقريب أم بحذف المنازل الزائدة؟ لا، إنها تقوم بالتقريب أيضًا، ولكنها تفعل ذلك بطريقة أنيقة.