انتقل إلى محتوى الدرس
الدرس 38
دورة PHP

الدوال ذات المعاملات المتغيرة وتفكيك المعاملات والدوال المتغيرة في PHPPHP Variadic Functions Argument Unpacking and Variable Functions

استقبل عدداً مرناً من المعاملات عبر معامل التجميع (...$args)، وفكك المصفوفات عند الاستدعاء، وتحقق من وجود الدوال بـ function_exists.
أقسام الدرس
6
الأمثلة
6
اللغة
العربية
تاريخ النشر
غير محدد
المشاهدات
0
محتوى الدرس
في هذا الدرس 6تصفّح المواضيع

إن وضع معامل النقاط الثلاث (...$items) قبل اسم المعامل ينشئ دالة ذات معاملات متغيرة تقبل صفراً أو أكثر من القيم وتجمعها تلقائياً داخل مصفوفة.

  • داخل جسم الدالة، يكون المتغير $items مصفوفة PHP عادية مرقمة من الصفر تحتوي على كل القيم الممررة.
  • إذا لم يمرر المستدعي أي قيمة للمعامل المتغير، تكون قيمة $items مصفوفة فارغة [].
  • تُغني الصيغة الحديثة ...$items تماماً عن الدالة القديمة func_get_args().

يجمّع ...$prices كل الأرقام الممررة في مصفوفة واحدة لكي تحسب array_sum($prices) مجموعها أياً كان عددها.

مخطط توضيحي: محاكي المعاملات المتغيرة (...$args) والتمرير بالمرجع والدوال المتغيرة في PHP
PHP
<?php
function calculateTotal(...$prices) {
    return array_sum($prices);
}

echo "3 items : " . calculateTotal(19.99, 5.01, 25.00) . "\n";
echo "0 items : " . calculateTotal() . "\n";

يمكن للدالة أن تشترط معاملات إلزامية ثابتة في البداية، ثم تلتقط جميع المعاملات الإضافية المتبقية في معامل متغير واحد يوضع في آخر قائمة المعاملات.

  • يُسمح فقط للمعامل الأخير في تعريف الدالة أن يكون متغيراً (function logLine($level, ...$messages)).
  • إن وضع أي معامل آخر بعد ...$messages يسبب خطأً فادحاً وقت الترجمة (Compile Error).
  • يضمن هذا النمط تزويد المعاملات الأساسية الإلزامية دائماً مع إبقاء عدد العناصر الإضافية مرناً.

يرتبط المعامل الأول "env" بالمتغير الثابت $prefix، بينما تُحزم القيم الثلاث المتبقية داخل المصفوفة $tags.

PHP
<?php
function buildTagList($prefix, ...$tags) {
    $formatted = [];
    foreach ($tags as $tag) {
        $formatted[] = $prefix . ":" . strtolower($tag);
    }
    return implode(", ", $formatted);
}

echo buildTagList("env", "Prod", "EU-West", "PHP84") . "\n";

عند استدعاء دالة، يؤدي وضع النقاط الثلاث ... قبل متغير المصفوفة إلى تفكيك عناصرها وتمرير كل عنصر كمعامل مستقل.

  • في تعريف الدالة يقوم ...$args بتجميع المعاملات في مصفوفة؛ أما عند استدعاء الدالة فيقوم ...$arr بتفكيك المصفوفة إلى معاملات منفردة.
  • في PHP 8.0+، يؤدي تفكيك مصفوفة ترابطية عند الاستدعاء إلى تمرير مفاتيحها النصية كمعاملات مسماة تطابق أسماء معاملات الدالة!
  • يغني تفكيك المعاملات بـ ... عن الدالة القديمة call_user_func_array() بصيغة أسرع وأوضح.

يفكك ...$indexed القيم حسب الترتيب، بينما يطابق ...$named المفاتيح النصية مع أسماء معاملات الدالة مباشرة.

PHP
<?php
function createServerUrl($host, $port, $scheme) {
    return "$scheme://$host:$port";
}

$indexed = ["api.closetag.com", 8443, "https"];
$named   = ["port" => 9000, "scheme" => "http", "host" => "localhost"];

echo createServerUrl(...$indexed) . "\n";
echo createServerUrl(...$named) . "\n";

افتراضياً يمرر PHP المتغيرات والمصفوفات بالقيمة. أما وضع الرمز (&$param) فيربط المعامل بالمتغير الأصلي للمستدعي بحيث يستمر أي تعديل خارج الدالة.

  • لا يمكن تمرير سوى متغيرات فعلية (مثل $counter) إلى معامل بالمرجع؛ وتمرير قيمة ثابتة مثل increment(5) يطلق خطأً فادحاً.
  • تستخدم دوال PHP المدمجة مثل sort(&$array) وarray_splice(&$array, ...) التمرير بالمرجع لتعديل المصفوفة في مكانها.
  • في الكود الحديث، يُفضل إرجاع القيمة الجديدة عبر return بدلاً من التعديل بالمرجع كلما أمكن ليكون مسار البيانات أوضح.

لأن &$price مُمرر بالمرجع، فإن طرح الخصم يحدّث قيمة المتغير الأصلي $cartSubtotal خارج الدالة إلى 170.

مخطط تدفق التنفيذ العملي لقسم تمرير المعاملات بالمرجع &$param لتعديل المتغير الأصلي في لغة PHP
PHP
<?php
function applyDiscount(&$price, $percent) {
    $discount = $price * ($percent / 100);
    $price -= $discount;
    return $discount;
}

$cartSubtotal = 200.00;
$saved = applyDiscount($cartSubtotal, 15);
echo "Saved: $$saved | New Subtotal: $$cartSubtotal\n";

في PHP، إذا كان المتغير يحمل اسماً نصياً لدالة وأتبعته بقوسين $fn()، يقوم PHP بالبحث عن تلك الدالة وتنفيذها ديناميكياً.

  • تحقق دائماً من وجود الدالة باستخدام function_exists($fn) أو is_callable($fn) قبل استدعائها عبر $fn().
  • بنى اللغة الأساسية مثل echo وisset وempty وunset وinclude ليست دوال ولا يمكن استدعاؤها كدوال متغيرة.
  • لا تنفذ أبداً نصاً قادماً من المستخدم كدالة متغيرة مباشرة؛ بل احصر الاستدعاءات في قائمة بيضاء محددة مسبقاً.

تتحقق function_exists($operation) من توفر الدالة strtoupper قبل أن يستدعيها التعبير $operation($input) ديناميكياً.

PHP
<?php
$operation = "strtoupper";
$input     = "closetag php 8.4";

if (function_exists($operation)) {
    echo "Result: " . $operation($input) . "\n";
}
echo "mb_strlen available? " . (function_exists("mb_strlen") ? "Yes" : "No") . "\n";

بدءاً من PHP 8.1، تتيح كتابة ثلاث نقاط داخل قوسي الدالة مثل strlen(...) أو trim(...) إنشاء مرجع مباشر للدالة يدعم الإكمال التلقائي في المحررات بدلاً من كتابة اسمها كنص.

  • على عكس كتابة اسم الدالة كنص ("trim")، تخضع صيغة trim(...) للفحص الثابت وتدعم إعادة التسمية الآمنة في بيئات التطوير.
  • لاحظ الفرق الدقيق: كتابة myFunc(...$arr) تستدعي الدالة فوراً بتفكيك المصفوفة، بينما كتابة myFunc(...) لا تستدعيها بل ترجع كائن Closure يشير إليها.
  • مرر هذا المرجع مباشرة إلى دوال مثل array_map(trim(...), $inputs).

تلتقط formatSku(...) إشارة مرجعية للدالة داخل $formatter دون تنفيذها، ثم تطبقها array_map() على كل عنصر.

الصيغةالمصطلحالسلوك البرمجي
function f(...$a)معامل متغير الطول (Variadic)يجمع الوسائط الممررة داخل مصفوفة $a
f(...$arr)تفكيك المصفوفة عند الاستدعاءيفكك عناصر $arr كوسائط مستقلة للدالة
function f(&$x)التمرير بالمرجع (By Reference)يعدّل المتغير الأصلي $x مباشرة
$fn($arg)دالة متغيرة (Variable Function)يستدعي الدالة التي يحمل المتغير النصي $fn اسمها
f(...)مرجع دالة من الدرجة الأولى (8.1+)يرجع كائن Closure يشير إلى الدالة f دون تنفيذها
PHP
<?php
function formatSku($raw) {
    return "SKU-" . strtoupper(trim($raw));
}

$formatter = formatSku(...);
$items     = ["  kb90 ", " ms20 "];
$mapped    = array_map($formatter, $items);

echo implode(" | ", $mapped) . "\n";
خلاصة المعرفة ومحطة الانتقال

ملخص الدرس

حصاد الدرس

مراجعة مركّزة لأهم المفاهيم والقواعد الهندسية التي أتقنتها في هذا الدرس قبل التطبيق العملي

ماذا تعلّمت في هذا الدرس؟

بدءاً من PHP 8.1، تتيح كتابة ثلاث نقاط داخل قوسي الدالة مثل strlen(...) أو trim(...) إنشاء مرجع مباشر للدالة يدعم الإكمال التلقائي في المحررات بدلاً من كتابة اسمها كنص. على عكس كتابة اسم الدالة كنص ("trim")، تخضع صيغة trim(...) للفحص الثابت وتدعم إعادة التسمية الآمنة في بيئات التطوير. لاحظ الفرق الدقيق: كتابة myFunc(...$arr) تستدعي الدالة فوراً بتفكيك المصفوفة، بينما كتابة myFunc(...) لا تستدعيها بل ترجع كائن Closure يشير إليها. مرر هذا المرجع مباشرة إلى دوال مثل array_map(trim(...), $inputs).

مشاركة

هل كان هذا الدرس مفيدًا؟

جارٍ تحميل الآراء…

ابنِ لغتك البرمجية

المصطلحات4

راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.

0 / 4 مفهومةأول بطاقة، أول خطوة
01 Variadics & Unpacking المعاملات المتغيرة ...$args
استقبل عدداً مرناً من المعاملات عبر معامل التجميع (...$args)، وفكك المصفوفات عند الاستدعاء، وتحقق من وجود الدوال بـ function_exists.
للمراجعة
02 Collecting Arguments with Variadic Splat تجميع المعاملات المتغيرة في مصفوفة عبر ...$args
المفهوم الأساسي لقسم تجميع المعاملات المتغيرة في مصفوفة عبر ...$args في لغة PHP الحديثة.
للمراجعة
03 Combining Fixed and Variadic Parameters دمج المعاملات الإلزامية مع المعامل المتغير الأخير
الصياغة البرمجية والتطبيق العملي المباشر لقسم دمج المعاملات الإلزامية مع المعامل المتغير الأخير.
للمراجعة
04 Unpacking Arrays into Function Arguments تفكيك عناصر المصفوفة وتمريرها عند استدعاء الدالة
قواعد التحقق وأفضل الممارسات القياسية الخاصة بقسم تفكيك عناصر المصفوفة وتمريرها عند استدعاء الدالة.
للمراجعة

اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.

حروف قليلة. معنى كامل.

الاختصارات4

راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.

0 / 4 مفهومةأول بطاقة، أول خطوة
01 PHP PHP
PHP: Hypertext Preprocessor
لغة البرمجة النصية على جانب الخادم لبناء تطبيقات الويب الديناميكية وواجهات البرمجة.
للمراجعة
02 CLI CLI
Command-Line Interface
واجهة سطر الأوامر التي تتيح تشغيل ملفات PHP مباشرة عبر الطرفية.
للمراجعة
03 FPM FPM
FastCGI Process Manager
مدير عمليات FastCGI عالي الأداء لمعالجة طلبات خادم الويب في PHP.
للمراجعة
04 HTML HTML
HyperText Markup Language
لغة الترميز القياسية التي يولدها محرك PHP ويرسلها إلى متصفح العميل بعد التنفيذ.
للمراجعة

اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.

من الفهم للتطبيق

مهامك قبل الاختبار

خطوة صغيرة كل مرة. وإنجاز تقدر ترجع له.

0/2مهام منجزة
  1. أنشئ ملف PHP محلياً ونفّذ المثال البرمجي المشروح في قسم تجميع المعاملات المتغيرة في مصفوفة عبر ...$args للتحقق من المخرجات.

  2. بدّل بين الحالات الثلاث في المحاكي التفاعلي ضمن قسم دمج المعاملات الإلزامية مع المعامل المتغير الأخير وقارن مخرجات التنفيذ.

تأشير المهمة إقرار منك بإتمامها، وليس تصحيحًا آليًا للكود. يُحفظ تقدمك في حسابك.

مساحة التحدي

اختبر فهمك.
ووصلها للإتقان.

كل سؤال خطوة لقدّام. اختار، اكتب كود، وشوف نتيجتك فورًا.

8أسئلة 1أنواع تحديات 100%هدف الإتقان
تصحيح تلقائي. فرص بلا حدود.

أكمل المهام، واجمع كل الإجابات الصحيحة. أقل من 100%؟ راجع وأعد المحاولة.

الأسئلة متاحة للاطلاع. سجّل الدخول للتفاعل وحفظ تقدمك.

لمحة عن التحدي8 أسئلة تنتظرك
01

أين يجب وضع المعامل المتغير (...$items) في قائمة معاملات الدالة في PHP؟

يُسمح للمعامل الأخير فقط أن يكون متغيراً ليعرف PHP أين تنتهي المعاملات الثابتة.

02

ما نوع البيانات للمتغير $numbers داخل الدالة function sum(...$numbers) عند استدعائها بدون معاملات sum()؟

يكون المعامل المتغير مصفوفة دائماً، وعند عدم تمرير قيم يكون مصفوفة فارغة [].

03

ماذا يحدث في PHP 8+ عند تفكيك مصفوفة ترابطية في استدعاء الدالة: calc(...["tax" => 5, "price" => 100])؟

في PHP 8.0+ ترتبط المفاتيح النصية عند التفكيك بأسماء المعاملات مباشرة.

04

كيف تعرّف معاملاً بحيث يؤدي تعديله داخل الدالة إلى تعديل المتغير الأصلي لدى المستدعي؟

يمرر الرمز & المعامل بالمرجع بدلاً من القيمة المستقلة.

05

ماذا يحدث إذا استدعيت دالة تستقبل معاملاً بالمرجع ومررت لها رقماً مباشراً مثل increment(10)؟

القيمة الثابتة مثل 10 ليست متغيراً قابلاً للتعديل بالمرجع.

06

أي دالة تتحقق مما إذا كان اسم الدالة المخزن في $fn معرّفاً وموجوداً قبل استدعائه عبر $fn()؟

ترجع function_exists() القيمة true إذا كانت الدالة المدمجة أو المخصصة معرفة.

07

لماذا يفشل الكود $fn = "echo"; $fn("Hello"); ويطلق خطأً فادحاً؟

البنى اللغوية مثل echo وisset وempty لا يمكن استدعاؤها كدوال متغيرة.

08

ماذا ترجع الصيغة strlen(...) (ثلاث نقاط داخل القوسين) في PHP 8.1+؟

تنشئ صيغة fnName(...) كائن Closure يمثل مرجعاً للدالة.