Menu

namespace ב-PHP: namespace, use וכינויים

namespace ב-PHP מקבץ מחלקות, פונקציות וקבועים תחת קידומת: namespace App\Models; בראש הקובץ, ואז use App\Models\User; במקום אחר כדי להתייחס למחלקה בשם הקצר שלה. למדו שמות מלאים, כינויים עם use ... as, use function, הלוכסן ההפוך המוביל למחלקות גלובליות וטעינה אוטומטית לפי PSR-4.

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

namespace ב-PHP שם מחלקות, פונקציות וקבועים תחת קידומת כך שהשמות שלהם לא יכולים להתנגש עם השמות של מישהו אחר. מצהירים עליו עם namespace App\Models; כפקודה הראשונה בקובץ, וקבצים אחרים מתייחסים למחלקה כ-\App\Models\User, או מייבאים אותה עם use App\Models\User; וכותבים רק User.

בתוך ה-namespace, User פירושו App\Models\User. User::class נותן את השם המלא כמחרוזת בלי ליצור שום דבר, וזה שימושי ללוגים ול-autoloaders.

שני namespaces בקובץ אחד

פרויקט אמיתי שם namespace אחד בכל קובץ. בהדגמה עצמאית, קובץ אחד יכול להחזיק כמה namespaces כשכל אחד עטוף בסוגריים מסולסלים. קוד שלא שייך לשום namespace נכנס ל-namespace { }:

שתי מחלקות בשם Order חיות זו לצד זו כי השמות המלאים שלהן שונים. זו בדיוק הבעיה ש-namespaces פותרים ברגע שמתקינים ספריות: ה-Order שלכם, ה-Order של ספריית תשלומים וה-Order של ספריית PDF כבר לא מתנגשים.

ייבוא עם use וכינוי עם as

כתיבה של \Shop\Order בכל מקום רועשת. use בראש קובץ (או בלוק namespace) מייבא שם כך שאפשר להשתמש בצורה הקצרה. כששני ייבואים היו מסתיימים באותו שם קצר, as נותן לאחד מהם שם אחר:

use רק יוצר שם קצר לשאר הקובץ. הוא לא טוען קובץ ולא מריץ קוד, והוא עובד אותו דבר בין אם המחלקה כבר קיימת ובין אם לא. מותרים גם ייבואים מקובצים: use Shop\{Order, Invoice};.

use function ו-use const

פונקציות וקבועים ב-namespace מיובאים עם use function ו-use const:

מחלקות גלובליות צריכות לוכסן הפוך

בתוך namespace, שם מחלקה בלי קידומת מתפרש ביחס ל-namespace הזה, ולכן new DateTime() בתוך namespace App; מחפש את App\DateTime. פונקציות וקבועים שונים: אם App\strlen לא קיימת, PHP נופלת חזרה ל-strlen הגלובלית. מחלקות אף פעם לא נופלות חזרה.

ה-catch (\Error $e) היה צריך לוכסן הפוך מאותה סיבה: בלעדיו PHP הייתה מחפשת את App\Error, אף פעם לא מתאימה לשגיאה האמיתית, והסקריפט היה נעצר עם Error שלא נתפס. תקנו את זה או עם לוכסן הפוך מוביל, כמו למעלה, או עם use DateTime; בראש הקובץ. אותו דבר חל על \Exception, על \Throwable ועל כל מחלקה מובנית אחרת; ראו try catch על תפיסה שלהן.

טעינה אוטומטית ו-PSR-4

בפרויקט, כל מחלקה חיה בקובץ משלה, ונתיב הקובץ עוקב אחרי ה-namespace. PSR-4 היא המוסכמה: קידומת של namespace ממופה לתיקיית בסיס, ושאר השם הופך לנתיב. autoloader שנרשם עם spl_autoload_register() טוען אז קובץ מחלקה בפעם הראשונה שמשתמשים במחלקה. הבלוק הזה כותב שני קובצי מחלקות לדיסק וטוען אותם אוטומטית:

כל קובץ מחלקה נטען פעם אחת, ברגע שהמחלקה נחוצה לראשונה. בפרויקטים אמיתיים לא כותבים את הפונקציה הזו בעצמכם: Composer מייצר אותה מכמה שורות ב-composer.json:

{
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    }
}

אחרי composer dump-autoload, require __DIR__ . '/vendor/autoload.php'; אחד בתחילת סקריפט הכניסה שלכם טוען כל מחלקה של App\... לפי דרישה.

כללי namespace שגורמים לשגיאות

  • namespace חייבת להיות הפקודה הראשונה בקובץ. רק declare(strict_types=1); והערות יכולים לבוא לפניה.
  • ייבואי use הם לכל קובץ בנפרד. ייבוא של מחלקה ב-index.php לא גורם לשם הקצר לעבוד בתוך קובץ שנכלל; כל קובץ צריך שורות use משלו.
  • use שייכת לרמה העליונה של הקובץ או של בלוק ה-namespace. בתוך גוף של מחלקה, ל-use יש משמעות אחרת: היא מושכת פנימה trait.
  • מחרוזות אף פעם לא מתפרשות: $class = 'User'; new $class(); מחפש את User הגלובלית. שמרו את השם המלא, רצוי עם User::class.

הכלל האחרון שווה בדיקה מהירה:

שאלות נפוצות

מה זה namespace ב-PHP?

קידומת שמקבצת מחלקות, ממשקים, פונקציות וקבועים קשורים, כמו תיקייה לשמות. namespace App\Models; בראש קובץ שם את המחלקה User שלו ב-App\Models\User, כך שהיא לא יכולה להתנגש עם User של ספרייה אחרת.

מה use עושה ב-PHP?

use App\Models\User; בראש קובץ מאפשר לכתוב User במקום השם המלא \App\Models\User בקובץ הזה. הוא לא טוען ולא כולל שום דבר; טעינת קובץ המחלקה היא העבודה של ה-autoloader. use ... as Alias; בוחר שם קצר אחר.

למה אני מקבל Class not found בתוך namespace?

בתוך namespace App; שם מחלקה בלי קידומת מתפרש ביחס ל-namespace, ולכן new DateTime() מחפש את App\DateTime. כתבו new \DateTime() או הוסיפו use DateTime; בראש הקובץ. פונקציות וקבועים נופלים חזרה למרחב הגלובלי אוטומטית, מחלקות לא.

מה הלוכסן ההפוך לפני שם מחלקה ב-PHP?

לוכסן הפוך מוביל הופך את השם למלא, שמתחיל מהמרחב הגלובלי: \Exception הוא תמיד ה-Exception המובנה של PHP, בכל namespace שבו הקוד נמצא. בלעדיו, השם מתפרש ביחס ל-namespace הנוכחי ולייבואים של use.

מה הקשר בין namespaces לתיקיות ול-PSR-4?

PHP עצמה לא קושרת namespaces לתיקיות. PSR-4 היא המוסכמה שעושה את זה: קידומת כמו App\ ממופה לתיקייה כמו src/, ולכן App\Models\User נמצאת ב-src/Models/User.php. ה-autoloader של Composer עוקב אחריה, ולכן השניים בדרך כלל תואמים.

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

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

להתחיל