Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

PHP: Composer, PSR та інструменти

20 питань · ~20 хв · Версія v3.0

Увійдіть, щоб продовжити

Обмеження версій і lock-файл, автозавантаження й оптимізація, скрипти й локальні пакети, стандарти PSR, PHPStan, Rector і Pint - питання всіх рівнів, від junior до lead.

За спробу
20
У пулі
42
Проходжень
0
Середній бал
-
Пройшли на 70%+
-

Питання для підготовки

14 питань
  • composer install ставить рівно ті версії, що записані в composer.lock. Нічого не оновлює.
  • composer update шукає найновіші версії, дозволені обмеженнями з composer.json, ставить їх і переписує composer.lock.

Звідси правило:

  • На проді, в CI і після git pull - лише install. Так у всіх однакові версії, і те, що перевірили тести, саме те, що поїде на сервер.
  • update - свідома дія розробника, щоб оновити залежності. Після неї ганяють тести і комітять новий composer.lock.
composer install --no-dev --optimize-autoloader   # прод
composer update laravel/framework --with-dependencies   # оновити один пакет

Пастка: composer update без аргументів оновлює все одразу. Якщо після нього щось зламалося, важко зрозуміти, який пакет винен. Краще оновлювати пакети поштучно чи невеликими групами.

Якщо composer.lock немає, install поводиться як update і створює його.

Докладніше в документації: Команди Composer

composer.json описує дозволені версії (^11.0 - будь-яка 11.x). composer.lock фіксує точні версії всіх пакетів, разом із залежностями залежностей, і хеші їхнього вмісту.

Для застосунку - комітити обов'язково. Інакше кожен composer install у колеги, в CI чи на сервері поставить «найновіше, що підходить», і версії поступово розійдуться. Баг «у мене працює» часто саме звідси.

Для бібліотеки (пакета, який ставлять інші) lock-файл зазвичай не комітять або він ні на що не впливає: застосунок, який ставить бібліотеку, однаково розв'язує версії сам, за своїм lock-файлом.

Що ще дає lock-файл:

  • composer install швидший, бо не треба розв'язувати залежності.
  • composer audit перевіряє на відомі вразливості саме встановлені версії.
  • Diff composer.lock у pull request показує, що реально оновилося.

Конфлікти в lock-файлі при злитті гілок не правлять руками: беруть версію однієї гілки й заново виконують ту composer require чи update, яка була в іншій.

Докладніше в документації: composer.lock у системі контролю версій

PSR-4 зіставляє префікс простору імен з каталогом. Решта імені класу перетворюється на шлях до файлу:

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

App\Services\Billing\Invoice → app/Services/Billing/Invoice.php.

Як це працює: vendor/autoload.php реєструє функцію через spl_autoload_register(). Коли код уперше звертається до невідомого класу, PHP викликає її, вона обчислює шлях і робить require. Класи, які не знадобилися в запиті, не завантажуються взагалі.

Що треба знати:

  • Регістр важливий: на Linux invoice.php для класу Invoice не знайдеться, хоча на macOS усе працюватиме. Класична причина «на проді клас не знайдено».
  • Один клас - один файл, ім'я файлу збігається з ім'ям класу.
  • Після зміни секції autoload у composer.json потрібен composer dump-autoload. Нові класи в уже налаштованому каталозі підхоплюються без нього.
  • Для файлів з функціями (не класами) є секція "files" - вони підключаються на кожному запиті.

Докладніше в документації: PSR-4 у composer.json

Обидва дозволяють оновлення, які за семантичним версіонуванням не мають ламати сумісність:

  • ^1.2.3 - від 1.2.3 до (не включно) 2.0.0. Дозволені всі мінорні й патч-оновлення.
  • ~1.2.3 - від 1.2.3 до (не включно) 1.3.0. Дозволені лише патчі.
  • ~1.2 - від 1.2 до 2.0. Остання вказана цифра може рости.

Нюанс з нулем: для версій 0.x мінорна версія вважається ламкою. ^0.3.1 - це від 0.3.1 до 0.4.0, а не до 1.0.

Що обирати:

  • ^ - стандарт для більшості залежностей. Саме його пише composer require.
  • Точна версія (1.2.3) - лише коли пакет відомий тим, що ламає сумісність у мінорних версіях, і оновлювати його хочеться тільки вручну.
  • * чи dev-master у застосунку - ні: сьогоднішній composer update може принести будь-що.

Важливо: обмеження в composer.json визначають, що дозволено. Що встановлено - записано в composer.lock, і на сервер їде саме воно.

Докладніше в документації: Версії й обмеження

За замовчуванням PSR-4 автозавантажувач для кожного класу обчислює шлях і перевіряє, чи існує файл. На тисячах класів ці перевірки файлової системи помітні.

Рівень 1 - classmap (composer install --optimize-autoloader або -o). Composer заздалегідь будує мапу «клас → файл» для всіх PSR-4/PSR-0 класів. Знайти клас - це один пошук у масиві, який до того ж лежить в OPcache.

Рівень 2 - authoritative classmap (--classmap-authoritative або -a). Те саме, але якщо класу немає в мапі, Composer не шукає його у файловій системі, а одразу вирішує, що класу немає. Швидше для перевірок class_exists() на неіснуючих класах.

Рівень 2/B - APCu (--apcu-autoloader). Знайдені шляхи кешуються в APCu. Альтернатива для випадків, коли authoritative не підходить.

composer install --no-dev --classmap-authoritative

Обмеження authoritative: класи, згенеровані під час виконання (проксі, скомпільовані шаблони в нестандартних місцях), не знайдуться, бо їх не було в мапі під час збирання. Тому його вмикають і перевіряють на стейджингу.

--no-dev теж допомагає: dev-залежності не потрапляють у мапу й не встановлюються на сервер.

Докладніше в документації: Оптимізація автозавантажувача

Прочитати - ще не значить знати

20 питань, по одному на екран, ~20 хв. Після завершення - розбір кожної помилки з посиланням на питання.