Многие пакеты представляют из себя приложения командной строки, так называемые cli-утилиты, взаимодействие (запуск команд, передача аргументов и опций, вывод результатов) которых с пользователем происходит интерактивным образом через терминал. Для обеспечения такой возможности (запуск файлов из командной строки) в Composer существует секция bin конфигурационного файла composer.json, например:

"bin": ["bin/php-package"]

Эта запись означает, что при установке пакета в операционной системе будет физически создан файл (а точнее, его особая разновидность — символическая ссылка) с именем php-package, запуск которого приведёт к запуску файла вашего проекта по адресу bin/php-package. Как можно заметить, имя ссылки задаётся именем файла (совпадает с ним). Также обратите внимание, что ссылок может быть множество (столько, сколько сами укажите в секции bin).

Месторасположение символической ссылки и способ её запуска из командной строки различаются в зависимости от способа установки пакета: глобального (с командой global: например, composer global vendor/package) или локального. Рассмотрим каждый случай отдельно.

Глобальная установка: генерация ссылок и запуск исполняемых файлов

При глобальной установке пакета, composer создаёт символические ссылки в каталоге $HOME/.composer/vendor/bin. То есть, при создании ссылок, в домашнюю директорию пользователя (от имени которого запускалась установка пакета) будет добавлен (если ещё не существует) каталог .composer/vendor/bin, куда и будут размещены ссылки. Это каталог по умолчанию, но путь к нему нам надо самостоятельно прописать в переменной окружения PATH. После этого мы можем запускать приложение по имени символической ссылки из командной строки, находясь в любой точке файловой системы (ведь при поиске исполняемых файлов командная оболочка ищет их последовательно по всем путям, прописанным в переменной окружения PATH).

В зависимости от версии composer директория по умолчанию может различаться. Кроме того, это значение можно конфигурировать. Посмотреть, в какую конкретно директорию composer складывает ссылки на исполняемые файлы можно с помощью команды composer global config bin-dir:

Посмотреть содержание переменной окружения PATH в вашей системе можно с помощью команды echo:

Пример

Давайте создадим и опубликуем пакет, который для краткости и наглядности будет очень простым, состоящим всего из двух исполняемых файлов, запуск которых выводит соответственно приветствие и прощание с Хекслетом.

Структура проекта:

~/projects/smallTalkWithHexlet$ ls -al
drwxrwxr-x 2 hex hex 4096 Jul  1 04:32 .
drwxrwxr-x 3 hex hex 4096 Jul  1 04:21 ..
-rw-rw-r-- 1 hex hex  225 Jul  1 04:31 composer.json
-rw-rw-r-- 1 hex hex    0 Jul  1 04:32 sayBye
-rw-rw-r-- 1 hex hex    0 Jul  1 04:32 sayHi

Содержимое исполняемого файла sayHi:

#!/usr/bin/env php
<?php

print_r("Hello, Hexlet!\n");

Содержимое исполняемого файла sayBye:

#!/usr/bin/env php
<?php

print_r("Bye-bye! See you later, Hexlet!\n");

Содержимое конфигурационного файла composer.json:

~/projects/smallTalkWithHexlet$ cat composer.json
{
    "name": "hex/small-talk-with-hexlet",
    "description": "Small talk with Hexlet",
    "keywords": ["hexlet", "php", "composer"],
    "license": "MIT",
    "bin": [
        "./sayHi",
        "./sayBye"
    ]
}

Небольшое отступление про исполняемые файлы:

  1. Для возможности запуска файла из командной строки у пользователя должно быть право на выполнение (атрибут x) этого файла.
  2. Если исполняемый файл содержит код, то надо указать командной оболочке интерпретатор, который будет исполнять этот код при запуске исполняемого файла. Это делается с помощью так называемого шебанга. В примере выше мы указали в качестве интерпретатора php, а путь к нему задали не абсолютный (в разных системах php может быть находится по совершенно разным путям), а с помощью специальной утилиты env.

Итак, мы подготовили пакет, и после публикации, он становится доступен для установки под именем hex/small-talk-with-hexlet.

Теперь установим этот пакет в систему глобально.

Но сначала убедимся, что никаких символических ссылок в директории не существует.

Здесь с помощью фильтра grep мы попытались найти файлы, содержащие в своём имени (как наши ссылки в секции bin) строчку "say". Но поиск не дал результатов, потому что таких файлов (до установки пакета) нет.

Далее глобально устанавливаем пакет в систему:

Теперь снова проверим с помощью grep директорию установки исполняемых файлов:

Как и ожидалось, в этом каталоге находятся символические ссылки (об этом свидетельствует первый символ l, определяющий тип файла в строке атрибутов файла lrwxrwxrwx), которые мы можем запускать из любой точки файловой системы:

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

Что происходит при локальной установке

В подавляющем большинстве случаев для целей разработки пакеты устанавливаются не глобально, а локально. При такой установке они "привязываются" к конкретному проекту и размещаются внутри его каталога по пути ./vendor/. При этом ссылки на исполняемые файлы устанавливаемых пакетов Composer размещает в каталоге ./vendor/bin.

Ссылки на исполняемые файлы локально установленных пакетов "заточены" на использование их в скриптах (секция scripts конфигурационного файла composer.json), для чего существует особенный синтаксис. Эту тему мы проходили в уроке, посвящённом скриптам.

Естественно, к символическим ссылкам можно также обратиться напрямую, указав нужный путь. Давайте рассмотрим это на примере, подключив к нашему разрабатываемому проекту small-talk-with-hexlet пакет PHP_CodeSniffer:

~/projects/smallTalkWithHexlet$ composer require --dev "squizlabs/php_codesniffer=*"

Если в корневом каталоге проекта установить какой-либо пакет с флагом --dev (composer require --dev some_package) — то он автоматически добавится в зависимости проекта: в секцию require-dev файла composer.json. Этой возможностью мы и воспользовались.

Как и ожидалось, появился каталог ./vendor, в котором лежит код подключённого пакета, а также других пакетов, от которых он, в свою очередь, зависит.

Узнать место, где composer хранит ссылки на исполняемые файлы локально подключаемых пакетов, позволяет команда composer config bin-dir (обратите внимание, что здесь нет команды global). В нашем случае это каталог ./vendor/bin, заглянем в него:

Как видно, при установке PHP_CodeSniffer добавилось два исполняемых файла для запуска разных программ. Давайте запустим phpcs (т.н. линтер — утилита, отвечающая за проверку кода на соответствие стандартам):

Программа отработала корректно и "молча" (без дополнительного вывода отчёта об ошибках), потому что в наших скромных файлах не было никаких нарушений оформления кода.

Затем была попытка запустить исполняемый файл из командной строки только по имени, но она привела к неудаче — bash: phpcs: command not found — командная оболочка просто не нашла его (в отличие от того, как это было бы при глобальной установке).

Заключение

В этом уроке мы рассмотрели как общие принципы, так и отдельные нюансы работы Composer с исполняемыми файлами проекта. Важно отметить, что эти принципы характерны для большинства других пакетных менеджеров из разных языков (например, менеджер пакетов Node.js в JavaScript). Поэтому, если в будущем вам придётся столкнуться с чем-то из них, то это не должно вызвать затруднений.

Мы учим программированию с нуля до стажировки и работы. Попробуйте наш бесплатный курс «Введение в программирование» или полные программы обучения по Node, PHP, Python и Java.

Хекслет

Подробнее о том, почему наше обучение работает →