طَبِّقْهاتعلّم المبدأ، وطبّقه بيدكمقرر 132 · تقنيات تطوير الواجهات الخلفية
الدرس 5 · الوحدة 2: الدوال

الدوال في PHP

الجاهزة منها وما تكتبه بنفسك، لتنظيم منطق الخادم. ⏱ نحو 30 دقيقة.

بعد هذا الدرس ستستطيع أن:
  • تستخدم أشهر الدوال الجاهزة للنصوص والأعداد والمصفوفات.
  • تعرّف دوالًا بمعاملات وقيم افتراضية وأنواع، وتعيد النتائج بـ return.
  • تشرح نطاق المتغيرات داخل الدالة وخارجها.
  • تبني قطع HTML بدوال صغيرة قابلة لإعادة الاستخدام.

١لماذا الدوال؟

الدالة Function كتلة كود لها اسم، تكتبها مرة وتستدعيها مرات. في الواجهة الخلفية تتكرر أعمال كثيرة: حساب الضريبة، وتنسيق السعر، والتحقق من البريد. لو كررنا الكود في كل صفحة، فأي تعديل سيحتاج تغيير كل النسخ.

وفي PHP نوعان: دوال جاهزة Built-in (أكثر من ألف دالة!)، ودوال تعرّفها أنت User-defined. ابدأ دائمًا بالبحث: «هل في PHP دالة جاهزة لهذا؟» والمرجع الرسمي php.net يشرح كل دالة بأمثلة.

٢دوال جاهزة للنصوص

<?php$name = "  سعود الحربي  ";$clean = trim($name);                 // يحذف المسافات من الطرفينecho "[" . $clean . "]\n";echo mb_strlen($clean) . " حرفًا\n";  // عدد الحروف (العربية صحيحة)echo strlen($clean) . " بايتًا\n";    // عدد البايتاتecho str_replace("الحربي", "العتيبي", $clean) . "\n";echo strtoupper("php") . "\n";echo str_contains($clean, "سعود") ? "موجود\n" : "غير موجود\n"; $csv = "قهوة,شاي,عصير";$items = explode(",", $csv);          // نص ← مصفوفةecho count($items) . " عناصر\n";echo implode(" | ", $items);          // مصفوفة ← نص
الدالةعملها
trim($s)تحذف المسافات والأسطر من بداية النص ونهايته. استخدمها مع كل حقل يصل من نموذج.
mb_strlen($s)عدد الحروف. لا تستخدم strlen مع العربية لأنها تعدّ البايتات.
str_replace($a, $b, $s)تستبدل كل $a بـ $b.
str_contains($s, $x)هل النص يحتوي $x؟ (PHP 8)
explode($sep, $s) و implode($sep, $a)تقسيم النص إلى مصفوفة، وتجميع المصفوفة في نص.

٣دوال جاهزة للأعداد والمصفوفات والتاريخ

<?php$prices = [35, 120, 45, 18];echo "المجموع: " . array_sum($prices) . "\n";echo "الأعلى: " . max($prices) . "\n";echo "المتوسط: " . round(array_sum($prices) / count($prices), 2) . "\n";echo "منسّق: " . number_format(1234567.891, 2) . "\n";echo in_array(45, $prices) ? "45 موجود\n" : "45 غير موجود\n"; sort($prices);                  // ترتيب تصاعدي (يغيّر المصفوفة نفسها)echo implode(", ", $prices) . "\n"; echo date("Y-m-d", 0) . "\n";   // تاريخ من طابع زمني

الدالة date("Y-m-d") بلا معامل ثانٍ تعطي تاريخ اليوم حسب ساعة الخادم. والرموز: Y للسنة، و m للشهر، و d لليوم، و H:i للساعة والدقيقة.

٤عرّف دالتك

تبدأ بالكلمة function، ثم الاسم، ثم المعاملات بين قوسين. والكلمة return تعيد النتيجة لمن استدعى الدالة:

<?phpfunction vat(float $price, float $rate = 0.15): float{    return round($price * $rate, 2);} function priceTag(float $price): string{    $total = $price + vat($price);    return number_format($total, 2) . " ريال";} echo "<p>الضريبة على 100: " . vat(100) . "</p>";echo "<p>بضريبة 5%: " . vat(100, 0.05) . "</p>";echo "<p>سعر القهوة شاملًا: " . priceTag(35) . "</p>";
الجزءالمثالمعناه
نوع المعاملfloat $priceيقبل عددًا فقط. إن أرسلت نصًّا غير رقمي يظهر خطأ واضح.
قيمة افتراضية$rate = 0.15إن لم يُرسل المعامل تُستخدم 0.15.
نوع القيمة المعادة: floatالدالة تعد بأن تعيد عددًا عشريًّا.
استدعاء دالة من دالةvat($price)priceTag تعيد استخدام vat بدل تكرار الحساب.

٥نطاق المتغيرات: الدالة عالم مغلق

المتغيرات المعرّفة خارج الدالة لا تُرى داخلها، والعكس صحيح. وهذا مختلف عن JavaScript وبايثون:

✗ خطأ
<?php$rate = 0.15; function vat($price){    return $price * $rate;}echo vat(100);
✓ صواب
<?php$rate = 0.15; function vat($price, $rate){    return $price * $rate;}echo vat(100, $rate);

الحل الصحيح: مرّر ما تحتاجه الدالة معاملًا. توجد الكلمة global لكنها تجعل الكود صعب التتبع، فتجنّبها.

والدالة تستقبل نسخة من القيمة؛ تعديل المعامل داخلها لا يغيّر المتغير الأصلي. هذا يحمي بياناتك من التغيير بالخطأ.

٦الدوال التي تبني HTML

في الواجهات الخلفية نكتب دوالًا صغيرة تعيد قطع HTML جاهزة، ثم نركّب الصفحة منها. لاحظ استخدام htmlspecialchars داخل الدالة نفسها، فلا ننساها أبدًا:

<?phpfunction e(string $s): string{    return htmlspecialchars($s);} function badge(string $text, string $color = 'gray'): string{    return "<span style='background:$color;color:#fff;padding:2px 8px;border-radius:9px'>" . e($text) . "</span>";} function productCard(array $p): string{    $status = $p['stock'] > 0 ? badge('متوفر', 'green') : badge('نفد', 'crimson');    return "<div style='border:1px solid #ccc;padding:8px;margin:6px'><b>" . e($p['name']) . "</b> $status<br>" . $p['price'] . " ريال</div>";} echo productCard(['name' => 'قهوة عربية', 'price' => 35, 'stock' => 5]);echo productCard(['name' => 'عسل سدر', 'price' => 120, 'stock' => 0]);

توقّع وتحقّق

أي دالة تحذف المسافات من طرفي النص؟

trim($s)

explode(",", "أ,ب,ج") تعيد:

تقسّم النص عند الفاصلة.

ما قيمة vat(200) إن عُرّفت function vat($p, $r = 0.15) { return $p * $r; } ؟

استُخدمت القيمة الافتراضية 0.15.

متغير عُرّف خارج الدالة، هل يُرى داخلها مباشرة؟

الدالة نطاق مغلق؛ مرّر القيمة معاملًا.

الخلاصة

تحدٍّ برمجي: فاتورة المتجر

متوسط

اكتب دالتين، ثم استخدمهما لطباعة فاتورة طلب. الدوال تجعل الحساب في مكان واحد.

المطلوب:
  • الدالة lineTotal(float $price, int $qty): float تعيد السعر × الكمية.
  • الدالة withVat(float $amount, float $rate = 0.15): float تعيد المبلغ مع الضريبة، مقرّبًا لخانتين بـ round.
  • للطلب الجاهز في الكود اطبع سطرًا لكل صنف: <li>قهوة عربية × 2 = 70</li>
  • ثم اطبع: <p>المجموع: 196</p> و <p>مع الضريبة: 225.4</p>
👀 اعرض الاستجابة المطلوبة
✓ التحقق الآلي: يرسل المختبر هذه الطلبات إلى خادمك بالترتيب ثم يفحص الاستجابات
  1. GET /invoice.php
  • الكود يعمل بلا أخطاء أو تحذيرات
  • سطر لكل صنف بالشكل المطلوب
  • المجموع: 196
  • مع الضريبة: 225.4
  • عرّفت الدالة lineTotal بنوعي المعاملين
  • عرّفت withVat بقيمة افتراضية 0.15 واستدعيتها

💡 تلميح 1
ابدأ بـ $sum = 0; واجمع فيه ناتج lineTotal لكل صنف داخل foreach.
💡 تلميح 2
round($amount * (1 + $rate), 2)

حاول بنفسك أولًا؛ للمسألة أكثر من حلّ صحيح.

<?php$order = [    ['name' => 'قهوة عربية', 'price' => 35, 'qty' => 2],    ['name' => 'تمر سكري', 'price' => 45, 'qty' => 2],    ['name' => 'شاي أخضر', 'price' => 18, 'qty' => 2],]; function lineTotal(float $price, int $qty): float{    return $price * $qty;} function withVat(float $amount, float $rate = 0.15): float{    return round($amount * (1 + $rate), 2);} $sum = 0;echo "<ul>";foreach ($order as $item) {    $line = lineTotal($item['price'], $item['qty']);    $sum += $line;    echo "<li>{$item['name']} × {$item['qty']} = $line</li>";}echo "</ul>";echo "<p>المجموع: $sum</p>";echo "<p>مع الضريبة: " . withVat($sum) . "</p>";
انتقل إلى تقييم الدرساختيار من متعدد، وصح وخطأ، وأكمل الفراغ، وتتبّع الناتج.ابدأ التقييم ←

📝 معلم؟ أرسل ملاحظة للمؤلف عن هذا الدرس