هذه أسئلة PHP الأكثر ظهورًا في المقابلات، مع إجابات قصيرة صحيحة لـ PHP 8.3 وشيفرة حيث توضح الشيفرة الفكرة. توقّع مخرجات كل كتلة قبل أن تضغط Run: هذا ما يختبره المقابل.
أسئلة مقابلات PHP للمبتدئين
ما هي PHP وكيف تعمل؟
PHP لغة برمجة نصية تعمل على الخادم. يمرر خادم الويب (Nginx أو Apache) الطلب إلى PHP (عادة PHP-FPM)، فتشغّل PHP السكربت من الأعلى، وكل ما تطبعه يصبح الاستجابة، عادة HTML. ويبدأ كل طلب من جديد: لا تبقى المتغيرات بين الطلبات ما لم تخزّنها في جلسة أو قاعدة بيانات أو ذاكرة تخزين مؤقت. وتشغّل PHP أيضًا السكربتات من سطر الأوامر (php script.php).
ما الفرق بين == و===؟
تقارن == بعد تحويل الأنواع، وتقارن === القيمة والنوع دون أي تحويل. يُظهر مثال الإحماء أعلاه == وهي تعمل: تُقارن النصوص الرقمية أعدادًا، لذا فإن '10' == '1e1' صحيحة true. ومنذ PHP 8، يُقارن العدد بالنص غير الرقمي على أنهما نصان، لذا فإن 0 == 'a' خاطئة false (وكانت true في PHP 7). انقر على الخلايا لتقارن العاملين:
| $a == $b | true | false | 0 | 1 | "0" | "1" | "" | null | [] | "a" | "10" | "1e1" |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| true | ||||||||||||
| false | ||||||||||||
| 0 | ||||||||||||
| 1 | ||||||||||||
| "0" | ||||||||||||
| "1" | ||||||||||||
| "" | ||||||||||||
| null | ||||||||||||
| [] | ||||||||||||
| "a" | ||||||||||||
| "10" | ||||||||||||
| "1e1" |
استخدم === افتراضيًا. وتستخدم in_array() وarray_search() المقارنة == ما لم تمرر true وسيطًا ثالثًا.
ما الفرق بين echo وprint؟
كلتاهما تخرج نصوصًا. تأخذ echo عدة وسائط (echo $a, $b;) ولا تعيد شيئًا؛ وتأخذ print وسيطًا واحدًا وتعيد 1، لذا يمكن استخدامها في تعبير. وليست أي منهما دالة، فالأقواس اختيارية. وعمليًا يستخدم الجميع echo.
علامتا التنصيص المفردتان مقابل المزدوجتين؟
تُدرج النصوص بين علامتي تنصيص مزدوجتين المتغيرات وتسلسلات الهروب: "Hi $name\n". والنصوص بين علامتي تنصيص مفردتين حرفية إلا \' و\\: تطبع 'Hi $name\n' تلك المحارف بالضبط. وفرق السرعة لا يُذكر، فالاختيار مسألة وضوح: المزدوجتان حين تُدرج متغيرات، والمفردتان حين لا تفعل.
ما أنواع البيانات في PHP؟
أربعة أنواع بسيطة (int وfloat وstring وbool)، ونوعان مركّبان (array وobject)، ونوعان خاصان (null وresource). أما callable وiterable وmixed وvoid فلا توجد إلا تصريحات أنواع، لا نوعًا لقيمة أبدًا. وتخبرك gettype() وget_debug_type() بنوع القيمة وقت التشغيل، وتطبعه var_dump() مع القيمة.
ما الفرق بين isset وempty وis_null؟
تكون isset($x) صحيحة true حين يوجد المتغير وليس null. وتكون empty($x) صحيحة true حين لا يوجد المتغير أو تكون قيمته خاطئة منطقيًا (0 و'0' و'' و[] وfalse وnull). وتكون is_null($x) صحيحة true لـ null، لكنها تحذّر مع متغير غير معرّف. أما isset وempty فلا تحذّران أبدًا، ولهذا تُستخدمان على مفاتيح المصفوفات.
| $x | isset | empty | is_null |
|---|---|---|---|
| null | |||
| false | |||
| 0 | |||
| "0" | |||
| "" | |||
| " " | |||
| [] | |||
| "a" | |||
| 0.0 |
الصف الذي يخطئ فيه الناس هو "0": النص صفر فارغ، بينما " " (مسافة) ليس فارغًا. وفي صفحة isset الجدول الكامل.
ما الفرق بين include وrequire؟
كلتاهما تُدرج ملفًا آخر وتشغّله. وإذا كان الملف مفقودًا، تطلق include تحذيرًا ويكمل السكربت، بينما ترمي require الخطأ Error ("Failed opening required")، الذي يوقف السكربت ما لم يلتقطه شيء. وتتخطى صيغتا _once (include_once وrequire_once) الملف الذي حُمّل من قبل، وهذا يمنع أخطاء "cannot redeclare function". استخدم require (أو require_once) للملفات التي لا يعمل السكربت دونها، وهي كلها تقريبًا؛ ويجعل المحمّل التلقائي في Composer معظم التضمينات اليدوية غير ضرورية.
ما الفرق بين GET وPOST؟
يرسل GET البيانات في نص الاستعلام في الرابط ($_GET)، فهي مرئية وقابلة للحفظ في المفضلة ومحدودة الطول؛ استخدمه للقراءة، مثل البحث والتقسيم إلى صفحات. ويرسل POST البيانات في جسم الطلب ($_POST)؛ استخدمه لكل ما يغيّر الحالة، مثل تسجيل الدخول أو الحفظ أو المدفوعات. ويجب ألا يغيّر طلب GET البيانات أبدًا، لأن الروابط تُجلب مسبقًا وتمر بها برامج الزحف.
ما هو عامل الدمج مع null؟
يعيد $a ?? $b القيمة $a إذا كانت موجودة وليست null، وإلا $b، دون تحذير لمتغير أو مفتاح غير معرّف: $page = $_GET['page'] ?? 1;. ولا يُسند ??= إلا حين يكون الطرف الأيسر null أو مفقودًا. ويختلف عن ?:، الذي يرجع إلى البديل مع أي قيمة خاطئة منطقيًا، لذا فإن 0 ?: 5 تساوي 5 لكن 0 ?? 5 تساوي 0.
أسئلة مقابلات PHP للمستوى المتوسط
ماذا يحدث حين تمر بالمرجع في foreach؟
تتيح لك foreach ($arr as &$v) تعديل العناصر في مكانها، لكن $v تبقى مرجعًا إلى العنصر الأخير بعد الحلقة. وإعادة استخدام الاسم في حلقة ثانية تكتب فوق ذلك العنصر:
العنصر الأخير 20، لا 30: أثناء الحلقة الثانية، تُسند إلى $v (التي ما زالت $arr[2]) القيمة 10، ثم 20، ثم قيمتها نفسها. احذف // قبل unset($v) وشغّله مرة أخرى. وتشرح صفحة foreach المراجع بالتفصيل.
ما الفرق بين الصنف المجرد والواجهة؟ وما هي السمة؟
الواجهة عقد: تواقيع توابع (وثوابت) دون تنفيذ، ويستطيع الصنف تنفيذ كثير منها. والصنف المجرد يمكن أن يحمل خصائص وبواني وتوابع مكتملة، إضافة إلى توابع مجردة يجب أن يكتبها أبناؤه؛ ولا يرث الصنف إلا واحدًا. والسمة مجموعة توابع تُنسخ إلى صنف بـ use، لإعادة استخدام الشيفرة بين أصناف ليس لها أب مشترك.
إجابة قصيرة يحبها المقابلون: استخدم الواجهة لتقول ما يستطيع الشيء فعله، والصنف المجرد لتشارك كيف يُفعل، والسمة حين تحتاج أصناف غير مترابطة إلى التوابع القليلة نفسها.
ما الفرق بين self وstatic؟
تشير self إلى الصنف الذي كُتبت فيه الشيفرة. وتشير static إلى الصنف الذي استُدعي فعلًا وقت التشغيل، ويُسمى هذا الربط الساكن المتأخر. ويهم ذلك في توابع الأب التي تنشئ «هذا النوع من الكائنات» أو تصفه:
تبني User::createStatic() كائن User. وتبني User::createSelf() كائن Model، وهذا يكسر نوع القيمة المعادة static، فترمي PHP الخطأ TypeError. ولهذا تستخدم توابع المصنع new static().
ما هي التوابع السحرية؟
توابع تستدعيها PHP نيابة عنك، تبدأ كلها بشرطتين سفليتين. والشائع منها: __construct() عند إنشاء كائن، و__destruct() عند تدميره، و__toString() عند استخدامه نصًا، و__get() و__set() للخصائص غير المتاحة، و__call() و__callStatic() للتوابع المفقودة، و__invoke() عند استدعاء الكائن مثل دالة، و__clone() بعد clone.
ما الفرق بين array_merge() والعامل +؟
تُلحق array_merge(): يُعاد ترقيم المفاتيح الرقمية وتستبدل المفاتيح النصية اللاحقة السابقة. أما + فاتحاد: يُبقي المصفوفة الأولى ولا يضيف إلا المفاتيح المفقودة، لذا مع مفتاح مكرر تفوز القيمة الأولى.
+ هو الأداة الصحيحة للقيم الافتراضية: تُبقي $options + ['timeout' => 30] ما مرره المستدعي وتملأ الباقي.
ماذا تفعل declare(strict_types=1)؟
دونها، تحوّل PHP الوسائط البسيطة إلى نوع المعامل المصرّح به حين تستطيع: تمرير "5" إلى معامل int يعطي 5. ومع declare(strict_types=1); جملةً أولى في ملف، يجب أن تمرر الاستدعاءات التي تجري من ذلك الملف النوع الدقيق، وإلا رُمي TypeError (وتمرير int إلى معامل float هو التوسيع الوحيد المسموح).
احذف سطر declare وشغّله مرة أخرى: يعيد الاستدعاء الثاني 10 بدل رمي خطأ.
ما الفرق بين الجلسة وملف تعريف الارتباط؟
يُخزَّن ملف تعريف الارتباط في المتصفح ويُرسل مع كل طلب، فيستطيع الزائر قراءته وتغييره. وتخزّن الجلسة البيانات على الخادم ولا تحتفظ إلا بمعرّف عشوائي في ملف تعريف ارتباط (PHPSESSID). ضع كل ما يجب الوثوق به، مثل معرّف المستخدم المسجل دخوله، في $_SESSION؛ وبعد تسجيل الدخول، استدعِ session_regenerate_id(true). وفي صفحة الجلسات وملفات تعريف الارتباط الشيفرة.
كيف تمنع حقن SQL؟
لا تبنِ SQL أبدًا بضم المُدخلات. استخدم الجمل المُعدّة، فتُرسل القيم منفصلة عن الاستعلام:
<?php
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ?');
$stmt->execute([$email]);
$user = $stmt->fetch();
لا تعمل العناصر النائبة إلا للقيم. ويجب فحص أسماء الجداول وأسماء الأعمدة وASC/DESC مقابل قائمة مسموحة قبل أن تدخل SQL. راجع PDO.
كيف تمنع XSS؟
هرّب المخرجات لا المُدخلات: ضع كل قيمة تُطبع في HTML داخل htmlspecialchars($value, ENT_QUOTES, 'UTF-8')، أو استخدم محرك قوالب يفعل ذلك تلقائيًا (Twig وBlade). وداخل <script>، استخدم json_encode() مع JSON_HEX_TAG. وأضف ترويسة Content-Security-Policy طبقةً ثانية.
كيف يجب تخزين كلمات المرور؟
بـ password_hash($password, PASSWORD_DEFAULT) وتُفحص بـ password_verify($password, $hash). وتستخدمان bcrypt (أو Argon2id) مع ملح عشوائي مخزّن داخل التجزئة وتكلفة مقصودة. وmd5() وsha1() خاطئتان لكلمات المرور لأنهما سريعتان ودون ملح. واستخدم password_needs_rehash() عند تسجيل الدخول لترقية التجزئات القديمة.
أسئلة مقابلات PHP المتقدمة
ما هي المولّدات ومتى تستخدم واحدًا؟
الدالة التي تحتوي yield تعيد Generator ينتج القيم واحدة واحدة، فقط عند الطلب. ويتيح لك المرور على تسلسل كبير أو لانهائي دون بناء مصفوفة في الذاكرة:
الاستخدامات المعتادة قراءة ملف كبير سطرًا سطرًا، وتدفق صفوف قاعدة البيانات، والسلاسل الكسولة. وتدعم المولّدات أيضًا المفاتيح (yield $key => $value)، والتفويض (yield from)، وتلقي القيم بـ send().
ما هي الدوال المغلقة، وماذا تفعل use؟
الدالة المجهولة (function () { ... }) كائن Closure. ولا ترى المتغيرات الخارجية ما لم تذكرها في use، التي تنسخ القيمة لحظة إنشاء الدالة المغلقة؛ وتلتقط use (&$x) بالمرجع بدلًا من ذلك. وتلتقط الدوال السهمية (fn ($x) => $x * $factor) المتغيرات الخارجية تلقائيًا، بالقيمة، وتحتوي تعبيرًا واحدًا.
ما الفرق بين abstract وfinal وreadonly؟
تعلّم abstract صنفًا لا يمكن إنشاء كائن منه، أو تابعًا يجب أن ينفّذه الابن. وتمنع final إعادة تعريف تابع أو وراثة صنف. وتجعل readonly (PHP 8.1) الخاصية قابلة للكتابة مرة واحدة فقط، من داخل الصنف، عادة في الباني؛ وأضافت PHP 8.2 أصناف readonly، التي تكون كل خاصية فيها readonly.
ما هو Composer، وما هو PSR-4؟
Composer مدير الاعتماديات في PHP: يسرد composer.json الحزم، ويثبّت composer.lock الإصدارات الدقيقة، ويحمّل vendor/autoload.php كل شيء. وPSR-4 هو معيار التحميل التلقائي الذي يربط بادئة فضاء أسماء بمجلد، فيعيش App\Mail\Mailer في src/Mail/Mailer.php ويُحمَّل عند أول استخدام. واشرح install (من ملف القفل) مقابل update (إصدارات جديدة، وملف قفل جديد).
ما الذي تغيّر في PHP 8؟
أبرز الميزات: في 8.0، الوسائط المسماة، وmatch، والعامل الآمن من null ?->، والأنواع الاتحادية، وترقية خصائص الباني، والسمات الوصفية (attributes)، وstr_contains()، ومقارنة أعقل بين النصوص والأعداد؛ وفي 8.1، التعدادات، والخصائص readonly، وصيغة الاستدعاء من الدرجة الأولى (strlen(...)) والألياف (fibers)؛ وفي 8.2، أصناف readonly والأنواع المستقلة null/true/false؛ وفي 8.3، ثوابت الأصناف ذات الأنواع، والسمة الوصفية #[\Override] وjson_validate()؛ وفي 8.4، خطافات الخصائص (property hooks)، والرؤية غير المتماثلة (public private(set))، وarray_find() وnew Foo()->method() دون أقواس محيطة. وصارت دوال كثيرة أيضًا ترمي TypeError أو ValueError بدل إعادة false مع تحذير.
كيف تدير PHP الذاكرة؟
لكل قيمة عداد مراجع؛ وحين ينخفض إلى الصفر، تُحرر الذاكرة فورًا. والكائنات التي يشير بعضها إلى بعض في دورة لا تصل إلى الصفر أبدًا، لذا يعمل جامع الدورات كلما امتلأ مخزنه المؤقت لجذور الدورات المحتملة (10,000 مدخل افتراضيًا) فيحررها (ويشغّله gc_collect_cycles() عند الطلب). والمصفوفات والنصوص تُنسخ عند الكتابة: يتشارك الإسناد $b = $a البيانات حتى يُعدَّل أحدهما. ولأن كل طلب يبدأ وينتهي نظيفًا، فإن تسرب الذاكرة يهم أساسًا في العمليات طويلة التشغيل ومستهلكي الطوابير.
كيف تُنفَّذ مصفوفات PHP؟
مصفوفة PHP خريطة تجزئة مرتبة: تحتفظ بترتيب الإدراج وتربط مفاتيح int أو string بالقيم، ولهذا يصلح النوع نفسه قائمةً وقاموسًا ومكدسًا. ويستغرق البحث بالمفتاح (isset($arr[$key])) زمنًا ثابتًا في المتوسط، بينما تفحص in_array() كل قيمة. وتُحوَّل المفاتيح النصية الشبيهة بالأعداد الصحيحة: $a['1'] و$a[1] العنصر نفسه.
مهام برمجة شائعة في المقابلات
تمارين قصيرة تُطلب كثيرًا مباشرة. كل دالة إجابة شائعة واحدة؛ شغّلها، وأضف مُدخلاتك (بما فيها المُدخل الفارغ)، وكن مستعدًا لشرح التعقيد الزمني، فهو عادة ما يفحصه المقابل.
الأسئلة الشائعة
كيف أستعد لمقابلة عمل مطور PHP؟
تأكد من أنك تستطيع شرح الأساسيات وكتابة شيفرتها دون البحث عنها: المقارنة والأنواع، والمصفوفات ودوالها، والبرمجة كائنية التوجه (الواجهات، والأصناف المجردة، والسمات، وstatic)، والاستثناءات، والأمان (الجمل المُعدّة، وhtmlspecialchars، وpassword_hash). ثم اعرف إطار عمل واحدًا (Laravel أو Symfony) وComposer بما يكفي للحديث عن مشروع بنيته.
أي إصدار من PHP يجب أن أعرفه للمقابلة؟
PHP 8. يتوقع المقابلون أن تعرف الميزات المضافة من 8.0 إلى 8.3: الوسائط المسماة، وmatch، والعامل الآمن من null ?->، والأنواع الاتحادية، وترقية خصائص الباني، والتعدادات، والخصائص readonly، وصيغة الاستدعاء من الدرجة الأولى. ولا تذكر سلوك PHP 7 إلا حيث تغيّر، مثل 0 == "a".
ما أسئلة PHP التي تُطرح على المبتدئين؟
غالبًا أساسيات اللغة: == مقابل ===، وecho مقابل print، وعلامتا التنصيص المفردتان مقابل المزدوجتين، وisset مقابل empty، وinclude مقابل require، وGET مقابل POST، والجلسات مقابل ملفات تعريف الارتباط، ومهام مصفوفات بسيطة مثل العكس أو التصفية أو عدّ القيم. وتوقّع تمرين برمجة قصيرًا واحدًا على الأقل.
ما أسئلة PHP التي تُطرح على المطورين ذوي الخبرة؟
التصميم والسلوك الداخلي: الواجهات مقابل الأصناف المجردة، والسمات، والربط الساكن المتأخر، والمراجع، والمولّدات والذاكرة، والاستثناءات ومعالجة الأخطاء، وحقن SQL والمعاملات، والتخزين المؤقت، والتحميل التلقائي في Composer، وكيف تبني ميزة أو تختبرها. ويُتوقع أن تأتي الإجابات مع الموازنات، لا مع التعريفات.