image\

Привет, Хабр! Сегодня я хотел бы поговорить с вами о знакомых опытным PHP-девелоперам, но загадочных для новичков, штуках — Composer и Packagist. Не сомневаюсь, что для многих здесь текст не станет откровением. Материал для тех, кому с описанным ниже только предстоит столкнуться.

Вы — PHP-разработчик, и вам нужен хороший менеджер зависимостей — как npm или Bundler? Вам надоело мучаться с pear? И вы не хотите вручную качать библиотеки с сайтов и обновлять все зависимости? Тогда самое время познакомиться с Composer и Packagist.


Основы


Начнем с объяснения, что такое Composer, а чуть позже поговорим и про Packagist. Composer — изначально менеджер зависимостей для PHP на уровне проекта. Это значит, что теперь нам не нужно мучиться с когда-то популярным pear, потому что для каждого проекта нужны свои версии библиотек и прочего. Теперь с помощью Composer все зависимости будут установлены в папку vendor в корне вашего проекта, и проекты не будут конфликтовать. Каждому проекту будет доступен свой набор установленных зависимостей.

Также в composer.json можно задать секцию scripts. Если грамотно ее использовать, можно получить легкий деплой-менеджер. Но изучение этой секции оставляю вам в качестве домашнего задания :).

Как это работает? Нужно просто создать файл composer.json в корне проекта и заполнить его согласно документации. Требуемый минимум в этом файле — набор зависимостей. По сути, это просто json-объект, ключ в котором — название нужного пакета, а значение — нужная для проекта версия. Для указания версий используется semver. Например, если для проекта нужны PHP минимум версии 5.4 и библиотека для логгирования monolog 1.9.*, нужно указать следующий объект require.

"require": {
    "php": ">=5.4.0",
    "monolog/monolog": "1.9.*"
}


Дальше просто нужно в командной строке выполнить команду composer update, и все новые зависимости будут подгружены в папку vendor, и вы сможете их использовать. Да, целиком PHP Composer не подтянет, но проверит, чтобы установленный на машине PHP был нужной версии. А если речь идет о библиотеках, Composer скачает пакет подходящей версии в папку vendor.

Представьте ситуацию: мы наконец-то внедрили в свой проект Composer, вовсю его используем, в общем, мы — молодцы! Но в какой-то момент приходим к ситуации, когда и у разработчиков и на сервере стоят разные версии библиотек. Как быть? Для этого composer рядом с composer.json создает файл composer.lock. В него после команды composer update записывается точная информация о версиях, которые установлены. Его нужно закоммитить в систему контроля версий, и таким образом все разработчики, а также на сервере можно просто выполнить команду composer install, и будут установлены все библиотеки точно таких версий, которые описаны в этом файле.

Пишем свой пакет


Любой желающий разработчик имеет право создать свой composer пакет и выложить в Open Source. Этот процесс я и хочу описать дальше.

Composer пакет по сути — это набор файлов, которые можно подключить в любой проект. Всё это можно отсортировать по папкам, как Вам только захочется. Главное, настроить автозагрузку composer. Какая же структура Composer пакета? Обязательным файлом для любого пакета является composer.json. Это файл в котором хранится вся информация про данный пакет: название, описание, список зависимостей, тип лицензии, и так далее. Вот пример composer.json простого пакета.

{
    "name": "dataart/package",
    "type": "library",
    "description": "Composer package by DataArt",
    "license": "MIT",
    "require": {
        "php": ">=5.4.0",
        "illuminate/support": "~4.2"
    },
    "autoload": {
        "psr-4": {
            "Dataart\\Package\\": "src/"
        }
    }
}


Name — имя пакета (формат vendor/name).
Type — тип пакета, данный пакет — библиотека
Description — описание пакета.
License — тип лицензии.
Require — список зависимостей данного пакета. Для него требуется версия PHP не менее 5.4.0 и пакет illuminate/support. Все версии описываются по semver.
Autoload — настройки автозагрузки. В данном случае указано, что неймспейс Dataart\Package начинается в папке src. Т. е. у всех файлов, которые лежат в папке src, должен быть неймспейс Dataart\Package. Если, например, хотите создать класс User и сохранить файл класса в папке Models, неймспейс класса User должен быть Dataart\Package\Models.

В папке src хранятся все нужные для работы пакета файлы. Рекомендуется рядом с папкой src сделать папку tests, и покрыть библиотеку тестами. Далее вся папка, в которой лежит composer.json, должна быть закоммичена на Github. Можно на Bitbucket, но все используют именно Github.

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

init

запустит для вас интерактивную инициализацию composer проекта и, задав несколько основных вопросов, сгенерирует composer.json-файл.

install

считывает composer.json, разрешает зависимости и устанавливает их в папку vendor. Если в папке есть файл composer.lock, будут использованы точные версии, указанные в файле. Это даёт возможность всем разработчикам иметь одинаковые версии всех библиотек.

update

используется, чтобы получить новые версии пакетов, тем самым обновить composer.lock. Также используется, если добавились новые зависимости. Может использоваться также с параметрами. composer update vendor/package1 vendor/package2 обновит только два пакета. Также можно обновить все пакеты одного вендора командой composer update vendor/*

require

добавляет новые зависимости из командой строки. Например, composer require vendor/package:2.* vendor/package2:dev-master. Если не указать версию, composer автоматически подтянет последнюю стабильную версию.

remove

точная противоположность require.

dump-autoload

обновить autoloader, если появились новые классы или правила автолоадинга.

К командам install, update и dump-autoload можно добавить ключ —optimize-autoloader (-o), чтобы конвертировать правила автозагрузки psr-0/4 в «карту классов», чтобы ускорить автозагрузку. Рекомендуется для production окружения.

Open Source It


Закоммитили? Круто, но composer всё равно почему-то не находит пакет и не может его подтянуть для другого проекта. Как быть?

Да, можно указывать конкретные адреса svn/git репозиториев в composer.json, но это неудобно. Намного удобнее иметь какой-то центральный пункт, где есть соответствия пакетов с их адресами репозиториев. Это Packagist.

Он используется для публикации composer пакетов. Опубликовать свой пакет туда очень легко. Достаточно зарегистрироваться на сервисе (или используя Github аккаунт через oAuth2), далее перейти по ссылке Submit Package, указать URL репозитория, а Packagist всё остальное сам подтянет и периодически будет проверять репозиторий на наличие новых версий.

Как происходит версионирование? Версионировать надо согласно системе semver. А указывать версии пакетов, используя тэги в системе контроля версий. Всё очень просто!

Создавайте свои пакеты, публикуйте их и становитесь полноценным участником Open Source сообщества.

Установить composer можно на getcomposer.org.

Посмотреть все доступные PHP-пакеты можно на packagist.org.

Комментарии (17)


  1. lesha_firs
    14.04.2015 18:02
    +2

    вот тоже хорошая стать habrahabr.ru/post/145946


  1. OnYourLips
    14.04.2015 20:26
    -7

    Программировать не PHP без composer — как быть водителем такси без автомобиля.


  1. t1gor
    14.04.2015 22:22
    +1

    Теперь с помощью Composer все зависимости будут установлены в папку vendor в корне вашего проекта

    Согласно документации, папку можно поменять — директивой «vendor-dir»

    Странно что вы не упомянули «require-dev», т.к. часто есть библиотеки которые нет смысла хранить на production сервере.


    1. hell0w0rd
      14.04.2015 22:34
      -2

      Согласно документации, папку можно поменять — директивой «vendor-dir»

      Что является плохой практикой, поэтому не стоит это упоминать.


      1. guyfawkes
        14.04.2015 22:47
        +2

        А по какой причине это плохая практика?


        1. Punk_UnDeaD
          14.04.2015 22:58
          -2

          Если структура проекта подразумевает папку vendor в корне, то плохая.
          А если не в корне, то хорошая.
          В Drupal пакетам следует находиться в «sites/all/vendor».


          1. guyfawkes
            15.04.2015 00:09
            +6

            Какие-то аргументы в пользу «хорошая» и «плохая» можно услышать?


      1. t1gor
        15.04.2015 00:44
        +3

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

        Какие-то аргументы в пользу «хорошая» и «плохая» можно услышать?

        Я бы тоже с удовольствием выслушал.


        1. hell0w0rd
          15.04.2015 01:47
          -3

          Задумываюсь. Но в любом проекте есть точка входа, composer помимо установки пакетов создает автолоадер, который нужно подключить в этой точке и больше не задумываться об этом.
          Если вы меняете название директории vendor, которая является стандартом для php, или node_modules для node — вы автоматически создаете сложности тем, кому этот проект нужно будет поддерживать. И совсем не важно, на каком фреймворке, или без него вы пишите.
          Если рассуждать так, как вы, то фантазией разработчика, уставшего от надоедливых пользователей может быть переименование сущности User на Monkey, вы тоже это считаете вполне себе нормальным?
          Вот пост на эту тему


          1. svscorp
            15.04.2015 09:28
            +2

            Если вы меняете название директории vendor, которая является стандартом для php

            А можно ссылочку на стандарт PHP для именования папки с зависимостями?

            Если вы меняете название директории vendor, которая является стандартом для php, или node_modules для node — вы автоматически создаете сложности тем, кому этот проект нужно будет поддерживать. И совсем не важно, на каком фреймворке, или без него вы пишите.
            Если рассуждать так, как вы, то фантазией разработчика, уставшего от надоедливых пользователей может быть переименование сущности User на Monkey, вы тоже это считаете вполне себе нормальным?


            Я не могу понять, как я создаю сложности тем, кто будет поддерживать проект? Если принимается решение об именовании папки vendor каким-либо другим именем, наверняка для этого есть причина?

            Существующий проект. Наверняка. Если есть причина, то, скорее всего, все те, кто поддерживает проект — вкурсе изменения
            Новый проект. Если я начинаю поддерживать какой-то проект, в котором изначально было принято решение о другом имени для папки с зависимостями, то какие трудности это создает для меня? :)

            Composer Vendor Directory пост

            «One True Vendor» — не сильный аргумент, а стремление автора к consistency. Там говорится о том, что папка vendor — «задумано по дизайну». И приводится «хорошая причина для такого дизайна»:
            Composer targets the PHP community. It aims to grow the library space. Libraries should be small, focused, flexible and avoid side-effects. The user should be in control.

            Если папка будет отлична от vendor — ничего не идет вразрез с «хорошим дизайном» (отсылка к тексту параграфа One True Vendor).

            «Autoloading» — не нашел сильных аргументов. Зато есть:
            A composer-managed application should have exactly one single include statement. A require vendor/autoload.php in the front controller

            Почему это не может быть «require vendor-dir/autoload.php» неясно.

            «Single directory» — тоже все весело. Особенно порадовало:
            Third, version control. No need to litter your gitignore with random garbage

            Т.е. папку vendor, создавая новый проект, совсем не надо добавлять ее в .gitignore :)

            Isolation — единственное «заключение» в нем это:
            Enough of that. That's why composer is a dependency manager and not a package manager. It manages deps per-project, it isolates them. It disallows sharing the same package directory between projects

            Как это связано с именованием папки зависимостей? Неясно. Зато — «мамой клянус!» («trust me, it's totally worth it») присутствует :)

            Итог
            Человек, написавший пост, явно устал от управления зависимостями с PEAR, особенно работая с несколькими проектами, которые зависят от разных библиотект. И он (человек) стремится к согласованности в именовании папки, что поощримо (я сам ЗА consistency в проектах). Но аргументов нет, есть только — «ппц, да это не круто именовать папку отлично от vendor».

            Я тоже предпочитаю «vendor», hell0w0rd, тем более, что пока не приходилось иметь дизайн приложения, который требовал бы изменения дефолтной конфигурации. Но я не исключаю возможности такой необходимости.
            И если все зависимости хранятся в одной папке, а не разбросаны по проекту — то по-сути все равно, какая эта папка (если уж дефолтное название изменено, возможно, есть на то причина).


          1. t1gor
            15.04.2015 10:06

            svscorp уже отлично ответил на Ваш комментарий и я с ним полностью согласен. От только одно забыл — если папка зависимостей не
            «vendor» — то путь к ней всегда можно посмотреть в composer.json и ее имя или положение относительно корня проекта не иммет никакого значения.


            1. svscorp
              15.04.2015 11:31
              +1

              Спасибо за дополнение про путь к папке.


  1. Punk_UnDeaD
    14.04.2015 22:53

    dump-autoload

    обновить autoloader, если появились новые классы или правила автолоадинга.


    Они не сами появляются и не сами изменяются, Файл composer/installed.json содержит сборную информацию об установленных пакетах и правилах автоподгрузки. Здесь правила можно исправить и dump-autoload будет исправленному верить.

    Некоторые пакеты содержат функции в глобальном пространстве имён. Просто так их не подключишь к чему угодно, конфликты будут.
    А исправив composer/installed.json запросто.


    1. t1gor
      15.04.2015 00:40

      Я думаю что автор имел в виду использование composer автозагрузки доя классов своего проекта, а не библиотек. В таком случае это очень даже имеет смысл.


  1. taliban
    16.04.2015 00:05
    +1

    «require»: {
    «php»: ">=5.4.0",
    «monolog/monolog»: «1.9.*»
    }

    Дальше просто нужно в командной строке выполнить команду composer update, и все новые зависимости будут подгружены в папку vendor, и вы сможете их использовать

    qwerty@qwerty ~/work/php/composer $ composer update

    [Seld\JsonLint\ParsingException]
    "./composer.json" does not contain valid JSON
    Parse error on line 1:
    «require»: { «php»: ">=5.
    --------^
    Expected one of: 'EOF', '}', ',', ']'


    Не серьезно ведь, вроде как и для новичков пишете, а если не знаком с композером то и не разберется сам.


    1. alexsoft Автор
      17.04.2015 19:41

      А не было сказано, что в данном коде указан валидный и полный json для файла composer.json. Описан только раздел require. Естественно, только эта часть не является валидным json.


      1. taliban
        17.04.2015 23:21

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