dr.Brain

doctor Brain

мир глазами веб-разработчика

Современный PHP разработчик (composer)

Пакетный менеджер composer

dr.Brain

время чтения 10 мин.

Photo by Dayne Topkin on Unsplash

Содержание


Пакетный менеджер

Обычно, функционально завершенный блок кода формирует метод, группа методов объединяется в составе определенного класса, набор классов составляет пакет.

Повторно используемые пакеты, в свою очередь, являются частью различных проектов, и не подвергаются, при этом, модификации. Такие пакеты позовляют решать строго опредленные задачи, обеспечивая взаимодействие с клиентом через API.

Использование пакетов способствует соблюдению современных принципов разработки программного обеспечения, например, DRY: “Don’t Repeat Yourself”, значительно уменьшая количество дублирующейся информации всех видов.

В большинстве случаев, у пакетов есть зависимости. Когда для работы “Пакета A” требуется “Пакет B”, мы говорим, что “Пакет A” зависит от “Пакета B”. Довольно часто для пакета формируется цепь таких зависимостей (“Пакет A” зависит от “Пакета B”, “Пакет B” зависит от “Пакета C”, список можно продолжить).

Представьте, что пакетных менеджеров не существует. Какие действия необходимо осуществить, для того чтобы обеспечить работоспособность “Пакета A”, зависящего от “Пакета B”? Для начала мы скачаем исходный код “Пакета A”, после чего обнаружим, что его функциональность зависит от “Пакета B”. Поэтому мы приложим максимум усилий, для того чтобы найти исходный код “Пакета B”. Но такой алгоритм может и не сработать, потому что мы не уверены, что в результате скачивания получим нужную версию “Пакета B”. Эту историю можно продолжить, а она касается только одной зависимости. Представляете, каким кошмаром обернется наличие у необходимого пакета множественных зависимостей или их цепочки.

                                                                                                                                                      Именно поэтому появилась необходимость в пакетном менеджере - инструменте, готовом взять на себя всю головную боль, связанную с поиском зависимых пакетов.

Composer vs. PEAR

PEAR

Кое-что с названием PEAR было еще до появляения Composer. Разработчики PHP с многолетним стажем наверняка знакомы с PEAR. Этот продукт сущестует с 1999 года. PEAR, как и Composer, был создан с целью развития инфраструктуры повторного использования пакетов. Тем не менее, по ряду причин он был отвергнут сообществом разработчиков:

  1. в отличии от Composer, PEAR - системный пакетный менеджер. В таком случае, имея несколько проектов с пакетами различных версий, использующими одинаковые зависимости, разработчики получали множество проблем,
  2. для того, чтобы пакет был размещен в репозитарии PEAR, требовалось собрать определенное количество голосов. Это условие воспринималось негативно и не способствовало росту репозитария. В конце концов, программист должен писать код, а не заниматься его популяризацией.

Composer

Composer - это пакетный менеджер уровня приложений для PHP. Его создатель вдохновился примерами NodeJS NPM и Ruby’s Bundler. В настоящее время этот пакетный менеджер признан всем сообществом PHP-разработчиков.

Экосистема Composer содержит две части:

  1. собственно Composer, который является утилитой командной строки для установки пакетов,
  2. Packagist - репозитарий пакетов.

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

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

Packagist

Как было написано выше, Packagist - дефолтный репозитарий пакетов для Composer. На момент написания этот статьи (ноябрь 2019) 244385 пакетов доступны для установки из этого репозитария. Каждый раз, перед тем как приступить к созданию с нуля какого-либо функционала на PHP, рекомендуется заглянуть в Packagist - скорее всего необходимая задача уже решена и пакет присутствует в репозитарии. Можно с уверенность сказать, что PHP-разработчики, использующие в своей работе Composer и Packagist, экономят кучу сил и времени.

Установка Composer

Существуют два варианта установки Composer: локальный и глобальный. Исходя из профессионального опыта, мы рекомедуем выбрать глобальную установку: скорее всего Вы будете использовать Composer для управления зависимостями во всех своих PHP-проектах. Глобальная установка избавляет от большого количества ненужных хлопот в перспективе.

Composer предлагает удобный установщик, который запускается из командной строки, актуальную версию можно взять здесь (в связи с тем, что инсталяционный код меняется по мере выхода новых версий продукта, нет смысла выкладывать его в этой статье).

MacOS/Linux/Unix

Для установки Composer требуется PHP версии 5.3.2+. Так же необходимо привести в соответствие некоторые настройки PHP, но нет смысла останавливаться на этом - установщик продукта предупредит о всех несовместимых параметрах. После успешной проверки настроек установщик скачает файл composer.phar в рабочую директорию.

PHAR - бинарный файл, формат архива для PHP, запускаемого из командной строки

Для глобальной установки composer.phar должен находиться в PATH. Поэтому сразу после удачного завершения работы установщика, необходимо выполнить следующую команду:

mv composer.phar /usr/local/bin/composer

Теперь для запуска пакетного менеджера достаточно набрать в консоли composer вместо php composer.phar.

Windows

Достаточно скачать и запустить установщик для Windows.

Актуальную информацию о глобальном и локальном вариантах установке Composer в различных операционных системах можно узнать здесь.

Проверка установки

Для того чтобы убедиться в том, что Composer установлен корректно, достаточно выполнить следующую команду (из директории установки - в случае локальной установки, из любой директории - в случае глобальной установки):

composer about

Если результат будет подобен этому, установка выполнена верно:

Composer - Dependency Manager for PHP
Composer is a dependency manager tracking local dependencies of your projects and libraries.
See https://getcomposer.org/ for more information.

Работа с Composer

Теперь Composer готов к работе. Рассмотрим небольшой пример:

Допустим, мы завершили работу над проектом, но для демонстрации его возможностей клиенту нужно сгенерировать пул даных: имена и адреса пользователей. Конечно, есть желание, чтобы такие данные выбирались случайным образом и, вообще, были максимально похожи на реальные. Одно из решений: самостоятельно создать массив имен и адресов, а затем случайным образом выбирать из него значения с помощью функции array_rand(). Надеюсь, Вы понимаете, что это непрактичное и скучное решение. А что делать, если нам понадобятся сотни пользовательских данных? Нужно найти альтернативное решение.

На помощь приходит Packagist - здесь есть пакет, который справится с поставленной задачей на сто процентов. Он даже называется Faker.

Давайте установим Faker с помощью Composer.

Из корневой директории проекта выполним команду:

composer require fzaninotto/faker

Для установки пакета потребуется всего лишь несколько секунд. За это время Composer скачает zip-архив Faker с GitHub и создаст несколько внутренних файлов и папок.

После установки пакета в директории проекта можно обнаружить новые папки и файлы:

  1. composer.json
  2. composer.lock
  3. vendor

composer.json

Этот файл описывает зависимости в проекте. Это просто JSON-файл, демонстрирующий установленные для данного проекта пакеты.

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


Рассмотрим три основные команды Composer:

composer require

Команда добавляет к зависимостям строго определенный пакет. Когда к проекту нужно добавить один пакет, достаточно аыполнить команду composer require. Это очень удобно, так как нет необходимости лишний раз модифицировать файл composer.json.

Другое предназначение этой команды - обновление версий уже установленных пакетов. Например, в проекте установлена последняя версия пакета Faker (1.8.0) с помощью команды:

composer require fzaninotto/faker

В случае, когда при выполнении команды composer require не указана необходимая версия пакета, происходит скачивание последней доступной версии.

Допустим, тестируемое приложение несовместимо с пакетом версии 1.8.0, но отлично работает с более ранней версией - 1.4.0. Для того, чтобы решить возникшую проблему достаточно выполнить команду:

composer require fzaninotto/faker:1.4.0

В этом случае произойдет не только скачивание пакета установленной версии, но и корректное обновление соответствующих файлов Composer.

composer install

Эта команда в первую очередь обращается к файлу composer.lock. Если данный файл присутствует, для указанных в нем пакетов будут установлены версии в строгом соответствии с версиями определенными в composer.lock, следует заметить, что для этих пакетов содержимое файла composer.json будет проигнорировано. Если файл composer.lock отсутствует, команда обратится к composer.json и установит последние версии пакетов в соответствии с ограничениями определенными в этом файле.

Возникает вопрос: в чем различия?

Когда используется composer.lock, происходит установка строго определенной версии пакета. Когда идет обращение к composer.json Composer всегда пытается скачать наиболее свежую версию, в соответствии с ограниченями определенными в файле. Когда версия пакета должна определятся через точное соответствие, эти методы ничем не отличаются друг от друга. Но абсолютное соответствие версий требуется крайне редко.

Эта команда обычно используется в 3 случаях:

  1. при старте нового проекта, когда в файле определены все зависимости и нужно скачать необходимые пакеты,
  2. когда идет размещение проекта из внешего репозитария (например, с GitHub), пакеты не хранятся в проекте, команда запускается, чтобы установить необходимые пакеты, в соответствии с настройками файлов Composer,
  3. в некоторых стратегиях переноса проекта из разработки в “боевую” среду.

composer update

Эта команда отличается от composer install тем, что обращается только к файлу composer.json. Таким образом, команда обновляет только пакеты, определенные в этом файле до последних версий в соответствии с установленными в composer.json ограничениями. Так же composer update устанавливает все новые пакеты, добавленные в composer.json.

Таким образом, composer update, как и composer require можно использовать для того, чтобы актуализировать версии пакетов. Но composer require не трубует внесения предварительных изменений в composer.json.

Команда composer update обращается только к информации в файле composer.json - это создает логическую ловушку при переносе проекта в “боевую” среду.

composer update никогда нельзя использовать на продакшене

Вот объяснение:

Ваше приложение успешно работает с пакетом Faker 1.4.0 в тестовой среде. Вы переносите проект в “боевые” условия и для установки пакетов запускаете composer update. Допустим, в файле composer.json определено нестрогое соответствие версии пакета Faker и имеет вид fzaninotto/faker: 1.*. Как результ, на продакшене окажется пакет Faker 1.8.0, несовместимый с данным приложением. То есть пакеты, в тестовой и боевой средах не будут идентичными. А это не тот результат, к которому мы стремимся.

Как избежать такой ситуации? Рекомендации просты:

  1. переносите composer.lock вместе с composer.json,
  2. в “боевой” среде используйте только composer install

Соблюдение этих нехитрых условий позволит вам быть уверенными в полном соответствии переносимых пакетов.

composer.lock

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

Тот факт, что composer install сначала обращается к composer.lock, делает эту команду безопасной и приоритетной для использования. И вот почему:

Рассмотрим следующую ситуацию. Случайно из проекта удалили папку vendor со всеми установленными пакетами. Что делать? Достаточно запустить команду composer install и будут установлены все необходимые версии пакетов, используемых в проекте.

Но есть и другой вопрос. Если мы используем систему контроля версий (например, git), нужно ли хранить в репозитарии файл composer.lock?

Это зависит от весьма простых условий:

  1. Обычно работа над проектом ведется в команде, и хочется быть уверенным в постоянной полной идентичности исходного кода в определенных ветках репозитария. Это означает, что composer.lock нужно коммитить и хранить в репозитарии.
  2. Когда идет работа над собственным пакетом или библиотекой, редко возникает необходимость в использовании команды composer install, в таком случае нет никакой необходимости в хранении в репозитарии файла composer lock.

Composer дает определенные свободы в использовании своих команд. Но существует несколько правил, которые лучше соблюдать, чтобы избежать неприятные ситуации:

  1. Зависимости определены в файле composer.json - используйте composer install.
  2. Есть необходимость в определенном пакете - используйте composer require some/package.
  3. Нужно установить несколько пакетов - определите их в composer.json и запустите composer update.
  4. Хотите протестировать новую версию определенного пакета - используйте composer rerquire some/package:new-version.
  5. Хотите протетсировать все новые версии установленных пакетов - используйте composer update.

Автозагрузка

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

Решение - автозагрузка. Это решение позволяет определить пути для поиска классов и избавить разработчика от рутинной работы, связанной с подключением файлов через include и require. Конечно, мы должны помнить, что на самом деле автозагрузка использует все те же управляющие конструкции include и require.

Но, давайте еще раз вернемся к нашему вымышленному проекту. Остался еще один вопрос, которого мы не коснулись. А именно, директория vendor, которую создает Composer. По умолчанию Composer сохраняет все пакеты именно в этой директории.

Кроме того Composer создает файл vendor/autoload.php, который обеспечивает автозагрузку кода установленных пакетов.

В нашем случае, для использования возможностей пакета Fake, достаточно просто подключить автозагрузчик:

require __DIR__ . '/vendor/autoload.php';

после этого Faker готов к работе:

$faker = Faker\Factory::create(); 
echo $faker->name;

Сообщество

Итак, Вы получили достатчные знания о менеджере зависимостей Composer. Приступайте к его использованию в своих проектах. Можно гарантировать, что это значительно облегчит Вашу работу, как личную, так и в составе команды. Не забывайте обращаться к Packagist, перед тем как приступить к созданию собственного функционала. Используйте все возможности сообщества.


Спасибо за внимание.

Новые публикации

Далее

Категории

О нас

Frontend & Backend. Статьи, обзоры, заметки, код, уроки.