Автозавантаження

Огляд

Автозавантаження — це концепція в PHP, коли ви вказуєте каталог або каталоги для завантаження класів. Це набагато корисніше, ніж використання require або include для завантаження класів. Це також вимога для використання пакетів Composer.

Правильне налаштування автозавантаження важливе і для розробки з підтримкою AI: агенти розміщують файли там, куди вказує простір імен. Якщо регістр папки та простору імен не збігаються, на Linux з'являтимуться помилки "клас не знайдено", навіть якщо все "працювало" на нечутливому до регістру диску Mac.

Розуміння

За замовчуванням будь-який клас Flight автозавантажується автоматично завдяки Composer. Для ваших класів застосунку є два поширені підходи:

  1. Composer PSR-4 (те, що використовує офіційний скелет): зіставте префікс простору імен з каталогом у composer.json, потім виконайте composer dump-autoload.
  2. Flight::path(): вкажіть завантажувачу Flight каталоги (зручно для простих застосунків або коли ви не використовуєте Composer для коду застосунку).

Використання автозавантажувача значно спрощує ваш код. Замість стіни include / require на початку кожного файлу класи завантажуються, коли ви вперше їх використовуєте.

Чутливість до регістру (прочитайте двічі)

Простори імен мають збігатися зі структурою каталогів і регістром літер цих каталогів.

Працює Ламається на Linux
App\Controller\HomeController → app/Controller/HomeController.php App\Controller\… з папкою app/controllers/
app\controllers\MyController → app/controllers/MyController.php Змішування App\ з нижнім регістром controllers

Простори імен PHP не чутливі до регістру в деяких контекстах, але Composer і файлова система — ні. Офіційний скелет стандартизує так:

  • Composer: "App\\": "app/"
  • Папки: Controller, Middleware, Model, Utils (PascalCase), а не controllers / middlewares

У старішій документації та прикладах спільноти іноді використовувався нижній регістр app\controllers. Це досі працює, якщо ваші папки в нижньому регістрі — але нові проєкти-скелети використовують App\ + папки PascalCase. Виберіть одну конвенцію для проєкту й дотримуйтеся її, щоб люди та AI-інструменти не створювали другу структуру.

Скелет (рекомендовано для нових проєктів)

Після composer create-project flightphp/skeleton код застосунку автозавантажується через Composer — Flight::path() не потрібен для класів App\:

{
  "autoload": {
    "psr-4": {
      "App\\": "app/"
    }
  }
}
// app/Controller/HomeController.php
namespace App\Controller;

use flight\Engine;

class HomeController
{
    protected Engine $app;

    public function __construct(Engine $app)
    {
        $this->app = $app;
    }

    public function index(): void
    {
        $this->app->render('welcome', ['message' => 'Hello!']);
    }
}
// app/config/routes.php — Dice розв'язує App\Controller\… через контейнер
$router->get('/', [HomeController::class, 'index']);

Дивіться Встановлення для повного дерева та AI та досвід розробника для інформації про те, як AGENTS.md документує цю структуру для помічників з кодування.

Базове використання (Flight::path())

Припустимо, у нас є дерево каталогів, подібне до наступного:

# Приклад шляху
/home/user/project/my-flight-project/
├── app
│   ├── cache
│   ├── config
│   ├── controllers - містить контролери для цього проєкту
│   ├── translations
│   ├── UTILS - містить класи лише для цього застосунку (цей каталог у верхньому регістрі навмисно, для прикладу нижче)
│   └── views
└── public
    └── css
    └── js
    └── index.php

Ви могли помітити, що це схоже на типове дерево застосунку (сайт документації використовує структурований макет). Нижній регістр controllers тут є допустимим вибором — це просто не поточний стандарт скелета.

Ви можете вказати кожен каталог для завантаження ось так:


/**
 * public/index.php
 */

// Додаємо шлях до автозавантажувача
Flight::path(__DIR__.'/../app/controllers/');
Flight::path(__DIR__.'/../app/utils/');


/**
 * app/controllers/MyController.php
 */

// простір імен не потрібен

// Усі автозавантажені класи рекомендується називати в Pascal Case (кожне слово з великої літери, без пробілів)
class MyController {

    public function index() {
        // щось робимо
    }
}

Простори імен з Flight::path()

Якщо у вас є простори імен, це насправді стає дуже простим. Ви повинні використовувати метод Flight::path() для вказівки кореневого каталогу (не кореня документа або папки public/) вашого застосунку.


/**
 * public/index.php
 */

// Додаємо шлях до автозавантажувача
Flight::path(__DIR__.'/../');

Тепер ось як може виглядати ваш контролер. Подивіться на приклад нижче, але зверніть увагу на коментарі з важливою інформацією.

/**
 * app/controllers/MyController.php
 */

// простори імен обов'язкові
// простори імен збігаються зі структурою каталогів
// простори імен мають відповідати регістру структури каталогів
// простори імен і каталоги не можуть містити символів підкреслення (якщо не встановлено Loader::setV2ClassLoading(false))
namespace app\controllers;

// Усі автозавантажені класи рекомендується називати в Pascal Case (кожне слово з великої літери, без пробілів)
// Починаючи з 3.7.2, ви можете використовувати Pascal_Snake_Case для назв класів, викликавши Loader::setV2ClassLoading(false);
class MyController {

    public function index() {
        // щось робимо
    }
}

І якщо ви хотіли автозавантажити клас у вашому каталозі utils, ви б зробили практично те саме:


/**
 * app/UTILS/ArrayHelperUtil.php
 */

// простір імен має відповідати структурі каталогів і регістру (зверніть увагу, що каталог UTILS у верхньому регістрі,
//     як у дереві файлів вище)
namespace app\UTILS;

class ArrayHelperUtil {

    public function changeArrayCase(array $array) {
        // щось робимо
    }
}

Простір імен у стилі скелета (ті самі правила, інший регістр)

/**
 * app/Controller/MyController.php
 */
namespace App\Controller;

class MyController {
    // ...
}

Правило не змінилося — змінився лише вибраний регістр папок/просторів імен у скелеті. Який би регістр ви не використовували для папок, ваш рядок namespace має йому відповідати.

Символи підкреслення в назвах класів

Починаючи з 3.7.2, ви можете використовувати Pascal_Snake_Case для назв класів, викликавши Loader::setV2ClassLoading(false);. Це дозволить вам використовувати символи підкреслення в назвах класів. Це не рекомендовано, але доступно для тих, кому це потрібно.

use flight\core\Loader;

/**
 * public/index.php
 */

// Додаємо шлях до автозавантажувача
Flight::path(__DIR__.'/../app/controllers/');
Flight::path(__DIR__.'/../app/utils/');
Loader::setV2ClassLoading(false);

/**
 * app/controllers/My_Controller.php
 */

// простір імен не потрібен

class My_Controller {

    public function index() {
        // щось робимо
    }
}

Дивіться також

Виправлення неполадок

  • Якщо ви не можете зрозуміти, чому ваші класи з просторами імен не знаходяться, пам'ятайте: за допомогою Flight::path() вказуйте корінь проєкту (або правильну базу для вашого простору імен), а не лише вкладену папку, яку ви забули віддзеркалити в просторі імен.
  • З Composer PSR-4 запустіть composer dump-autoload після зміни зіставлень у composer.json.
  • На Linux CI або у продакшені неправильний регістр папки — дуже поширена помилка "працює на моїй машині".

Клас не знайдено (автозавантаження не працює)

Це може статися з кількох причин. Нижче наведено кілька прикладів.

Неправильна назва файлу

Найпоширеніша причина — назва класу не збігається з назвою файлу.

Якщо у вас є клас з назвою MyClass, то файл має називатися MyClass.php. Якщо у вас є клас з назвою MyClass, а файл називається myclass.php, то автозавантажувач не зможе його знайти.

Неправильний простір імен або регістр папки

Якщо ви використовуєте простори імен, простір імен має відповідати структурі каталогів, включно з регістром.

// ...код...

// якщо ваш MyController знаходиться в app/Controller (скелет) і має простір імен App\Controller
// це не працюватиме:
Flight::route('/hello', 'MyController->hello');

// Стиль скелета:
use App\Controller\MyController;
Flight::route('/hello', [ MyController::class, 'hello' ]);

// Старіший макет з нижнім регістром (тільки якщо ваші папки насправді app/controllers):
use app\controllers\MyController;
Flight::route('/hello', [ MyController::class, 'hello' ]);
// або повністю кваліфікований:
Flight::route('/hello', [ 'App\Controller\MyController', 'hello' ]);

path() не визначено (код застосунку без Composer)

Якщо ви покладаєтеся на Flight::path() замість Composer для класів застосунку, визначте шлях перед маршрутами, які посилаються на ці класи (часто на початку bootstrap або public/index.php):

// Додаємо шлях до автозавантажувача (корінь проєкту для застосунків з просторами імен)
Flight::path(__DIR__.'/../');

Офіційний скелет переважно використовує Composer PSR-4 для App\, тому зазвичай вам не потрібен Flight::path() для контролерів і моделей там.

Журнал змін

  • Документація – Документування скелета App\ + папок PascalCase і проблем із чутливістю до регістру для людей та AI-інструментів.
  • v3.7.2 - Ви можете використовувати Pascal_Snake_Case для назв класів, викликавши Loader::setV2ClassLoading(false);
  • v2.0 - Додано функціонал автозавантаження.