Composer: всё, что я должен был знать | OTUS
Запланируйте обучение с выгодой в Otus!
-15% на все курсы до 30.11 Забрать скидку! →
Выбрать курс

Composer: всё, что я должен был знать

Материал является переводом статьи «Composer: everything I should have known».

Композер — это то, что я использовал для запуска своих проектов и установки дополнительных библиотек. Никогда об этом не задумывался — это просто работало. Иногда я сталкивался с проблемами, но зачастую они решали запуском composer install или composer dump-autoload. Я понятия не имел, как работает dump-autoload, но это помогало.

В этой статье рассказывается обо всём, что мне хотелось бы знать о композере. Вы узнаете, почему мы используем его, как он работает, что вы можете с ним делать, и как использовать его в продакшне.

Время PEAR

До композера мы полагались на cherry-pick кода из одного места в другое или вручную загружали библиотеки и бросали их в каталог libs. Новым решением стал PEAR (PHP Extension and Application Repository) — набор существующих в то время библиотек.

Но с этим было много проблем:

  1. Установка делалась в масштабах всей системы, а не одного проекта. Вы не могли держать несколько версий одной библиотеки на компьютере.
  2. Каждая библиотека должна быть уникальной. Вам недоступно было предложить решение для специфичной проблемы.
  3. Чтобы ваш репозиторий был принят в PEAR, нужно было набрать определённое количество голосов.
  4. Существующие решения были часто устаревшими, неактивными или неподдерживающимися.

Время композера

Разработанный Nills Adermann и Jordi Boggiano композер решил все проблемы, которые не мог решить PEAR. Пакеты устанавливаются отдельно для каждого проекта и любой программист может свободно вносить, создавать и делиться пакетами со всем миром. Это привело к появлению более отточенных, полных и свободных от ошибок библиотек. Композер является менеджером зависимостей. Он обращается к файлу конфигурации (composer.json) для определения зависимостей вашего проекта и их подзависимостей, откуда их загружать, а также когда устанавливать и загружать их.

Зависимости — это не только php-библиотеки. Это также могут быть требования к платформе: например, версия php и расширения, установленные на вашем компьютере. Они не могут быть установлены через композер — их единственная цель — информировать разработчиков о том, как должна выглядеть их среда.

Откуда приходят пакеты?

Пакеты могут быть установлены из любого места, если они доступны через VCS (систему контроля версий, такую ​​как git или svn), PEAR или прямой URL-адрес файла .zip. Для этого вы должны указать свои источники в разделе repositories, используя собственную конфигурацию. Для приватных репозиториев вы можете настроить композер на использование токенов доступа или базовой http-аутентификации. Доступны параметры конфигурации для GitHub, Gitlab и Bitbucket. Если репозитории не были указаны или пакеты не были найдены с использованием предоставленных источников, композер выполнит поиск в своем основном хранилище packagist.org. Как только пакет найден, композер использует функции VCS (ветви и теги), чтобы найти и попытаться загрузить лучшее соответствие для ограничений версии, указанных в файле composer.json.

Подожди минуту! Попытка? Лучшее соответствие?

Ну да. Существуют разные способы указать, какие версии пакетов должен устанавливать композер. Но прежде чем мы углубимся в это, давайте кратко рассмотрим, как большинство разработчиков создают версии своих пакетов, следуя соглашению SemVer (семантическое управление версиями). SemVer помогает разработчикам сообщать о характере изменений, внесенных в их пакет. Таким образом, всем, кто полагается на это, не нужно вручную проверять исходный код на наличие изменений, которые могут нарушить их проект. Соглашение предполагает наличие версии из трех частей X.Y.Z (Major.Minor.Patch) с необязательными суффиксами стабильности.

Каждое число начинается с 0 и увеличивается в зависимости от типа изменений:

  • Major.Minor.Patch — Major увеличивается при внесении критических изменений;
  • Major.Minor.Patch — Minor увеличивается при добавлении обратно-совместимых функций;
  • Major.Minor.Patch — Patch увеличивается, когда ошибки были исправлены/
  • иногда используются суффиксы стабильности: -dev, -patch (-p), -alpha (-a), -beta (-b) или -RC (релиз-кандидат).

Предостережения

Пакеты, имеющие основную версию в 0.x.x, могут вносить критические изменения во время минорных релизов. Только пакеты с версией 1.0.0 или выше считаются готовыми к продакшну. Не все пакеты следуют семантическому версионированию. Обязательно ознакомьтесь с их документацией, прежде чем делать какие-либо предположения.

Ограничения версий

Существует множество способов указать версии пакета, но наиболее распространенными из них являются:

  1. Диапазон версий — с помощью математических операторов>,> =, <, <=,! = = 1.0.0 <2.0.0 можно установить последнюю версию выше или равную 1.0.0, но ниже 2.0.0.
  2. Диапазон каретки (^) — при добавлении каретки будет установлена ​​новейшая доступная версия, которая не содержит критических изменений. ^ 2.1.0 переводится как "установить самую новую версию выше или равную 2.1.0, но ниже, чем 3.0.0".
  3. Диапазон тильды (~) — аналогичен диапазону каретки; разница в том, что это только увеличивает версию последнего указанного числа: ~ 2.1 установит самую последнюю версию 2.x (например, 2.9); ~ 2.1.0 установит самую новую версию 2.1.x (например, 2.1.9).
  4. Можно также указать точную версию.

Вы можете зарегистрировать зависимости в двух разных местах: require и require-dev. Require содержит все, что нужно вашему проекту для запуска в проде, тогда как require-dev определяет дополнительные требования для разработки — например, phpunit для запуска набора тестов. Причина, по которой мы указываем зависимости в двух разных местах, заключается в том, что мы не устанавливаем и не загружаем пакеты, предназначенные для разработки — на рабочих машинах.

Вот, что мы имеем в composer.json:

{
    "require": {
        "php": "^7.1.3",
        "ext-gd": "*",
        "lib-libxml": "*",
        "monolog/monolog": "^1.12"
    },
    "require-dev": {
        "fzaninotto/faker": "^1.4",
        "phpunit/phpunit": "^7.5"
    }
}

Требования к prod-окружению — версия PHP между 7.1.3 и 8.0.0 (не включительно). Необходимо установить расширение gd (графическое изображение) и библиотеку libxml вместе с любой версией между 1.1.2 и 2.0.0 (не включительно) пакета monolog/monolog.

Требования к dev-окружению — fzaninotto/faker между 1.4 и 2.0 (не включительно) и phpunit/phpunit между 7.5 и 8.0 (не включительно).

Почему диапазон версий?

Почему я должен определять диапазон версий, а не конкретную версию?

При указании точных версий сложно поддерживать зависимости вашего проекта в актуальном состоянии, что создает риск пропуска важных патчей. Использование диапазона позволит композеру добавлять новые версии, содержащие исправления багов и патчи безопасности.

Хорошо, но все делают ошибки. Некоторые пакеты могут по-прежнему вносить серьезные изменения в минорные релизы. Не означает ли это, что когда я запущу composer install на продакшн-компьютере, есть шанс, что мой проект будет разрушен из-за критических изменений, внесенных каким-то случайным пакетом?

Здесь начинается файл composer.lock. Как только вы запустили установку в первый раз, точные версии ваших зависимостей и их субзависимостей будут сохранены в файле composer.lock — это означает, что все последующие установки будут загружать точно такие же версии, избегая ошибки, описанной выше. Единственный случай, когда композер пытается угадать, какие версии пакета нужно загрузить, это когда вы запускаете команду install в первый раз или когда файл composer.lock теряется. Если вы не пишете библиотеку, вы всегда должны сохранять файл composer.lock в системе контроля версий. Запуск composer update будет действовать так, как будто файл блокировки не существует. Композер выполнит поиск любых новых версий, которые соответствуют определённым вами ограничениям и перепишет файл composer.lock с новыми обновленными версиями.

Автозагрузка композера

Композер создает файл vendor/autoload.php, который можно включить в проект и начать использовать классы, предоставляемые установленными пакетами, без дополнительных усилий. Вы даже можете добавить свой собственный код в автозагрузчик, добавив ключ автозагрузки в composer.json. Ниже пример того, что вы можете сделать автолоад с помощью композера:

{
 "autoload": {
  "psr-4": {
   "Foo\": "src/"
  },
  "classmap": [
   "database/seeds",
   "database/factories",
   "lib/MyAwesomeLib.php"
  ],
  "files": ["src/helpers.php"],
  "exclude-from-classmap": ["tests/"]
 }
}

Здесь:

  • PSR-0 и PSR-4 являются стандартами, используемыми для преобразования пространств имен классов в физические пути к файлам, которые их содержат. Например, всякий раз, когда мы пишем use Foo\Bar\Baz;, композер автоматически загружает файл, расположенный в src/Foo/Bar/Baz.php;
  • classmap — содержит список файлов классов и каталогов для автозагрузки.
  • files — содержит список файлов для автозагрузки. Это особенно полезно, когда у вас есть набор функций, которые вы хотите использовать глобально на протяжении всего проекта;
  • вы также можете исключить некоторые файлы и каталоги из автозагрузки, добавив их в exclude-from-classmap.

А как насчет пользовательских скриптов?

Скрипт композера может быть обратным вызовом PHP, определенным как статический вызов метода, или любой другой допустимой исполняемой командой командной строки. Их можно запускать вручную с использованием composer yourScriptName или подключать к различным событиям, генерируемым в процессе работы композера. Например, после создания нового проекта Laravel, композер создает копию файла .env.example в .env, а затем запускает команду php artisan key:generate, чтобы сгенерировать и установить ключ приложения в только что скопированном файле .env.

{
    "scripts": {
        "post-root-package-install": [
            "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
        ],
        "post-create-project-cmd": [
            "@php artisan key:generate --ansi"
        ]
    }
}

Вы также можете ссылаться на другие скрипты композера. В приведенном ниже тестовом сценарии мы вызываем скрипт clearCache для удаления каталога кэша перед запуском наших тестов с использованием phpunit.

{
    "scripts": {
        "test": [
            "@clearCache",
            "phpunit"
        ],
        "clearCache": "rm -rf cache/*"
    }
}

Композер в продакшне

Вот ряд рекомендаций, которые я рекомендую вам соблюдать при использовании композера на проде:

  1. Никогда не запускайте composer update на продакшне. Сделайте это на компьютере разработчика, чтобы убедиться, что все работает. Только после этого делайте коммит ваших изменений, сделайте pull на продакшн-компьютер и запустите composer install, чтобы запустить новые версии, определенные в файле composer.lock.
  2. Разделите зависимости вашего проекта на требования к продакшну и требования к разработке с помощью ключей require и require-dev. Таким образом, композер не будет устанавливать пакеты, предназначенные для разработки (например, phpunit) в производственной среде. Убедитесь, что вы загружаете только те файлы и каталоги, которые вам нужны. Как и в случае с requirements, вы также можете разделить автозагрузку на продакшн и разработку, используя ключи autoload и autoload-dev. Нет никаких причин автоматически загружать каталоги миграций в продакшн.
  3. Используйте composer install —no-dev —optimize-autoloader для установки пакетов и оптимизации автозагрузчика для продакшна. Флаг —no-dev указывает композеру игнорировать пакеты только для разработки, в то время как флаг —optimize-autoloader преобразует динамическую автозагрузку PSR-0 / PSR-4 в статический classmap. Это ускоряет загрузку файлов, поскольку с помощью classmap автозагрузчик точно знает, где находится файл, а при использовании PSR-0 / PSR-4 он всегда должен проверять, существует этот файл или нет.

Это всё. Все, что нужно знать о композере — по крайней мере, с точки зрения пользователя. Если вы заинтересованы в том, как создать и опубликовать пакет на packagist.org, вот хороший учебник для подражания.

Не пропустите новые полезные статьи!

Спасибо за подписку!

Мы отправили вам письмо для подтверждения вашего email.
С уважением, OTUS!

Автор
0 комментариев
Для комментирования необходимо авторизоваться
Популярное
Сегодня тут пусто
Черная пятница в Otus! ⚡️
Скидка 15% на все курсы до 30.11 →