تشغّل include 'header.php'; شيفرة ملف PHP آخر في ذلك الموضع من السكربت، كأنها ملصقة هناك. وتفعل require 'header.php'; الشيء نفسه، لكن إذا تعذر تحميل الملف، توقف require السكربت بخطأ فادح بينما تكتفي include بطباعة تحذير وتكمل. والاستخدام الأول المعتاد ترويسة وتذييل تتشاركهما كل الصفحات.
تكتب الكتلة header.php وfooter.php أولًا، ليوجد ما يُضمَّن. شغّلها وانظر إلى تبويب Page:
الملفات المُضمَّنة ملفات PHP عادية: يمكن أن تحتوي HTML مع وسوم <?= ?>، وترى المتغير $title المضبوط قبل require. غيّر العنوان وشغّله مرة أخرى؛ وكل صفحة تتطلب الترويسة ستلتقط أي تغيير في ذلك الملف الواحد.
include مقابل require
الفرق الوحيد هو ما يحدث حين يكون الملف مفقودًا أو غير قابل للقراءة. تطبع include تحذيرين، وتكون قيمتها false، ويكمل السكربت:
Warning: include(sidebar.php): Failed to open stream: No such file or directory in /home/index.php on line 2
Warning: include(): Failed opening 'sidebar.php' for inclusion (include_path='.:/usr/share/php83') in /home/index.php on line 2
وتطبع require التحذير نفسه ثم ترمي Error، ينهي السكربت ما لم يلتقطه شيء:
PHP Warning: require(config.php): Failed to open stream: No such file or directory in /home/index.php on line 2
PHP Fatal error: Uncaught Error: Failed opening required 'config.php' (include_path='.:/usr/share/php83') in /home/index.php:2
لذا استخدم require لكل ما لا تعمل الصفحة دونه (الإعدادات، ومكتبات الدوال، وملفات الأصناف) وinclude للأجزاء الاختيارية. وللجزء الذي قد يغيب لسبب مشروع، افحص وجوده أولًا بدل الاعتماد على التحذير:
المخرجات:
Spring sale: 20% off
banner.php included, include returned int(1)
sidebar.php not found, skipped
include_once وrequire_once
الملف الذي يعرّف دالة أو صنفًا لا يمكن تحميله إلا مرة واحدة: تحميله مرة ثانية خطأ فادح، لأن الدالة موجودة أصلًا.
Fatal error: Cannot redeclare greet() (previously declared in /home/helpers.php:2) in /home/helpers.php on line 2
يحدث ذلك حالما يتطلب ملفان كلاهما require 'helpers.php'. تتذكر require_once وinclude_once الملفات التي حُمّلت من قبل وتتخطاها في المرة الثانية، معيدة true:
المخرجات:
int(1)
bool(true)
bool(true)
Hello, Ada
استخدم صيغ _once للملفات التي تصرّح بأشياء، وinclude العادية للقوالب التي تريد إخراجها أكثر من مرة. وفي المشاريع التي تستخدم Composer، يحمّل المحمّل التلقائي ملفات الأصناف نيابة عنك، فتختفي معظم استدعاءات require_once للأصناف؛ راجع Composer.
إعادة قيمة من ملف مُضمَّن
توقف return في المستوى الأعلى من ملف مُضمَّن ذلك الملف وتعيد قيمة إلى تعبير include أو require. وهذا يصنع ملف إعدادات نظيفًا: لا متغيرات عامة، بل قيمة تسندها إلى أي اسم تريده.
المخرجات:
My Shop
shop
bool(false)
تعمل ملفات إعدادات Laravel (config/app.php وconfig/database.php وبقيتها) بهذه الطريقة.
المتغيرات والنطاق في الملفات المُضمَّنة
تعمل الشيفرة المُضمَّنة في نطاق السطر الذي يضمّنها. في أعلى السكربت ترى كل متغير عام؛ وداخل دالة لا ترى إلا المتغيرات المحلية لتلك الدالة. وهذه القاعدة الثانية هي طريقة عمل عارض قوالب صغير: دالة متغيراتها المحلية هي بالضبط المتغيرات التي يجب أن يراها القالب.
يعرض تبويب Page القائمتين، مرسومتين من ملف قالب واحد. ولأن include تعمل داخل render()، يرى القالب $heading و$products لكن لا يرى $secret. وصيغة foreach ... endforeach المستخدمة في القالب هي الصيغة البديلة التي تقدمها PHP لقوالب HTML.
مسارات التضمين و__DIR__
لا يُحل مسار مثل 'helper.php' نسبةً إلى الملف الذي يحتوي include. تبحث PHP في إعداد include_path (الذي يبدأ عادة بـ .، مجلد العمل الحالي) ثم فقط في مجلد الملف المُضمِّن نفسه. لذا داخل partials/nav.php، قد تحمّل include 'helper.php' ملف helper.php مختلفًا تمامًا من جذر المشروع. ويزيل __DIR__، مجلد الملف الحالي، التخمين:
المخرجات:
loaded the root helper.php
loaded partials/helper.php
__DIR__ in nav.php is partials
اكتب كل تضمين على شكل __DIR__ . '/relative/path.php'. فمجلد العمل يعتمد على طريقة بدء السكربت (خادم الويب، أو مهمة cron، أو سطر الأوامر من مجلد آخر)، لكن __DIR__ لا يتغير أبدًا.
لا تضمّن أبدًا ملفًا يسمّيه المستخدم
من أوائل الموجّهات الشائعة قراءة اسم الصفحة من الرابط: include $_GET['page'] . '.php';. وهذا يتيح للزائر اختيار أي ملف على الخادم يعمل، مثل ?page=../../config (تضمين ملف محلي)، ومع الإعدادات القديمة حتى ملفًا من خادم آخر. اربط الأسماء المسموحة بالملفات بدلًا من ذلك. شغّل الكتلة وانقر على الروابط: كل نقرة تشغّل السكربت من جديد مع $_GET['page'] مختلفة.
لا يمكن أن يصل إلى require إلا الأسماء الثلاثة في $pages؛ ويحصل رابط ../secret على صفحة "Not found". وقراءة قيم الطلب بأمان مشروحة في _POST.
الأسئلة الشائعة
ما الفرق بين include وrequire في PHP؟
كلتاهما تحمّل ملف PHP آخر وتشغّله. وإذا تعذر تحميل الملف، توقف require السكربت بخطأ فادح، بينما تطبع include تحذيرًا وتعيد false وتدع السكربت يكمل. استخدم require للملفات التي لا تعمل الصفحة دونها، مثل الإعدادات ومكتبات الدوال.
متى أستخدم require_once بدل require؟
استخدم require_once للملفات التي تعرّف دوال أو أصنافًا أو ثوابت. فتحميل مثل هذا الملف مرتين خطأ فادح (Cannot redeclare)، وتتخطى require_once الملف إذا كان قد حُمّل من قبل. أما القوالب التي تريد طباعتها عدة مرات فتستخدم include العادية.
هل يمكن لملف PHP مُضمَّن أن يعيد قيمة؟
نعم. تنهي return في المستوى الأعلى من الملف المُضمَّن الملف وتصبح قيمة تعبير include أو require: $config = require 'config.php'; مع return ['debug' => true]; في config.php. ودون return، تكون قيمة include هي 1.
هل يصل الملف المُضمَّن إلى متغيراتي؟
نعم. تعمل الشيفرة المُضمَّنة في نطاق السطر الذي يضمّنها: في أعلى السكربت ترى المتغيرات العامة، وداخل دالة ترى المتغيرات المحلية لتلك الدالة ولا شيء غيرها. والمتغيرات التي تنشئها تقع في النطاق نفسه.
هل أكتب include('file.php') أم include 'file.php'؟
كلتاهما تعمل، لأن include وrequire بنيتان لغويتان لا دالتان؛ والأقواس تحيط بالمسار فقط. وتكتب معظم أدلة الأسلوب require 'file.php'; دونها.