Menu

include ו-require ב-PHP: טעינת קובצי PHP אחרים

include 'header.php'; מריצה קובץ PHP אחר בנקודה הזו, כאילו הקוד שלו הודבק שם. require עושה את אותו הדבר אבל עוצרת את הסקריפט עם שגיאה קטלנית כשהקובץ חסר, בעוד include רק מזהירה וממשיכה. include_once ו-require_once טוענות קובץ רק בפעם הראשונה.

בדף הזה יש עורכים שאפשר להריץ - לערוך, להריץ ולראות את הפלט מיד.

include 'header.php'; מריצה את הקוד של קובץ PHP אחר בנקודה הזו בסקריפט, כאילו הוא הודבק שם. require 'header.php'; עושה את אותו הדבר, אבל אם אי אפשר לטעון את הקובץ, require עוצרת את הסקריפט עם שגיאה קטלנית בעוד include רק מדפיסה אזהרה וממשיכה. השימוש הראשון הרגיל הוא header ו-footer שמשותפים לכל הדפים.

הבלוק כותב קודם את header.php ואת footer.php, כדי שיהיו קבצים לכלול. הריצו אותו והסתכלו בלשונית Page:

הקבצים הנכללים הם קובצי PHP רגילים: הם יכולים להכיל HTML עם תגיות <?= ?>, והם רואים את המשתנה $title שהוגדר לפני ה-require. שנו את הכותרת והריצו שוב; כל דף שעושה require ל-header היה מקבל שינוי בקובץ האחד הזה.

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, ה-autoloader טוען בשבילכם קובצי מחלקות, ולכן קריאות require_once למחלקות נעלמות ברובן; ראו Composer.

החזרת ערך מקובץ שנכלל

return ברמה העליונה של קובץ שנכלל עוצר את הקובץ הזה ומוסר ערך בחזרה לביטוי ה-include או ה-require. זה יוצר קובץ הגדרות נקי: בלי משתנים גלובליים, רק ערך שמציבים לכל שם שרוצים.

פלט:

My Shop
shop
bool(false)

קובצי ההגדרות של Laravel (config/app.php, config/database.php והשאר) עובדים כך.

משתנים וטווח בקבצים שנכללו

קוד שנכלל רץ בטווח של השורה שכוללת אותו. בראש סקריפט הוא רואה כל משתנה גלובלי; בתוך פונקציה הוא רואה רק את המשתנים המקומיים של הפונקציה הזו. הכלל השני הוא האופן שבו renderer תבניות זעיר עובד: פונקציה שהמשתנים המקומיים שלה הם בדיוק המשתנים שהתבנית צריכה לראות.

הלשונית Page מציגה את שתי הרשימות, שרונדרו מקובץ תבנית אחד. כיוון ש-include רצה בתוך render(), התבנית רואה את $heading ואת $products אבל לא את $secret. הצורה foreach ... endforeach שבשימוש בתבנית היא התחביר החלופי ש-PHP מציעה לתבניות HTML.

נתיבי include ו-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

כתבו כל include כ-__DIR__ . '/relative/path.php'. תיקיית העבודה תלויה באופן שבו הסקריפט הופעל (שרת ה-web, משימת cron, שורת הפקודה מתיקייה אחרת), אבל __DIR__ אף פעם לא משתנה.

לעולם אל תכללו קובץ שהמשתמש קבע את שמו

נתב ראשון נפוץ קורא את שם הדף מכתובת ה-URL: include $_GET['page'] . '.php';. זה מאפשר למבקר לבחור איזה קובץ בשרת ירוץ, למשל ?page=../../config (local file inclusion), ועם הגדרות ישנות אפילו קובץ משרת אחר. מפו במקום זאת שמות מותרים לקבצים. הריצו את הבלוק ולחצו על הקישורים: כל לחיצה מריצה את הסקריפט שוב עם $_GET['page'] אחר.

רק שלושת השמות שב-$pages יכולים להגיע אי פעם ל-require; הקישור ../secret מקבל את דף ה-"Not found". קריאה בטוחה של ערכי בקשה מוסברת ב-GETו−_GET ו-_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'; בלעדיהם.

איור של שפות התכנות ב-Coddy

ללמוד תכנות עם Coddy

להתחיל