Platform requirements
Composer позволяет указывать требования к платформе — версии PHP и расширений. Это гарантирует, что пакет будет установлен только в совместимом окружении.
{
"require": {
"php": ">=8.4",
"ext-pdo": "*",
"ext-mbstring": "*",
"ext-intl": "*",
"ext-redis": "^6.0",
"ext-openssl": "*",
"lib-openssl": ">=1.1"
}
}
Типы platform requirements
| Префикс | Описание | Пример |
|---|---|---|
php |
Версия PHP | "php": ">=8.4" |
ext-* |
PHP-расширение | "ext-pdo": "*" |
lib-* |
Системная библиотека | "lib-openssl": ">=1.1" |
composer |
Версия Composer | "composer": ">=2.7" |
Эмуляция платформы
Иногда локальная среда отличается от production. Например, вы разрабатываете на PHP 8.4, а на сервере PHP 8.3. Секция config.platform позволяет эмулировать другую платформу:
{
"config": {
"platform": {
"php": "8.3.0",
"ext-redis": "6.0.0"
}
}
}
Теперь Composer будет разрешать зависимости так, будто у вас PHP 8.3. Это предотвращает установку пакетов, несовместимых с production.
# Check what platform Composer sees
composer show --platform
# Override platform temporarily
composer install --ignore-platform-req=ext-redis
composer install --ignore-platform-reqs # Ignore all platform requirements
Типы репозиториев
Composer поддерживает несколько типов репозиториев для загрузки пакетов.
VCS Repository
Самый простой способ подключить приватный пакет из Git-репозитория:
{
"repositories": [
{
"type": "vcs",
"url": "[email protected]:mycompany/auth-service.git"
},
{
"type": "vcs",
"url": "https://github.com/mycompany/shared-kernel.git"
}
],
"require": {
"mycompany/auth-service": "^2.0",
"mycompany/shared-kernel": "dev-main"
}
}
Composer автоматически определяет теги как версии, а ветки как dev-версии (dev-main, dev-feature/xxx).
Path Repository
Подключает пакет из локальной директории. Идеально для монорепозиториев и локальной разработки:
{
"repositories": [
{
"type": "path",
"url": "../shared-kernel",
"options": {
"symlink": true
}
}
],
"require": {
"mycompany/shared-kernel": "@dev"
}
}
При symlink: true Composer создаёт символическую ссылку вместо копирования файлов. Изменения в пакете сразу видны без composer update.
Composer Repository
Для подключения к приватным Composer-репозиториям (Satis, Private Packagist):
{
"repositories": [
{
"type": "composer",
"url": "https://packages.mycompany.com",
"options": {
"ssl": {
"verify_peer": true
}
}
}
]
}
Package Repository
Для пакетов, которые не имеют composer.json (например, legacy-библиотеки):
{
"repositories": [
{
"type": "package",
"package": {
"name": "vendor/legacy-lib",
"version": "1.0.0",
"dist": {
"url": "https://example.com/legacy-lib-1.0.0.zip",
"type": "zip"
},
"autoload": {
"classmap": ["src/"]
}
}
}
]
}
Приоритет репозиториев
Репозитории проверяются в порядке объявления. Первый репозиторий, содержащий пакет, побеждает. Packagist проверяется последним (можно отключить):
{
"repositories": [
{
"type": "composer",
"url": "https://packages.mycompany.com"
},
{
"packagist.org": false
}
]
}
Aliases — псевдонимы версий
Branch Aliases
Позволяют дать dev-ветке семантическую версию:
{
"extra": {
"branch-alias": {
"dev-main": "3.0.x-dev",
"dev-develop": "3.1.x-dev"
}
}
}
Теперь dev-main воспринимается как версия 3.0.x-dev, и другие пакеты могут требовать ^3.0.
Inline Aliases
Используются в require для замены версии:
{
"require": {
"monolog/monolog": "dev-bugfix-123 as 3.5.0"
}
}
Composer установит ветку bugfix-123, но для разрешения зависимостей будет считать, что это версия 3.5.0. Полезно при тестировании фиксов из feature-веток.
composer create-project
Команда create-project создаёт новый проект из пакета. Это эквивалент git clone + composer install:
# Create Symfony project
composer create-project symfony/skeleton my-symfony-app
# Create Laravel project
composer create-project laravel/laravel my-laravel-app
# Create with specific version
composer create-project symfony/skeleton:"7.2.*" my-app
# Create in current directory
composer create-project symfony/skeleton .
# Create without dev dependencies
composer create-project --no-dev symfony/skeleton my-app
# Create with preferred stability
composer create-project --stability=dev symfony/skeleton my-app
Внутренний процесс:
- Загружает пакет с Packagist
- Извлекает в указанную директорию
- Выполняет
composer install - Запускает
post-create-project-cmdскрипты
Оптимизация автозагрузки
В production критически важно оптимизировать автозагрузчик для максимальной производительности.
Три уровня оптимизации
# Level 1: Optimized autoloader
# Generates a classmap for all PSR-4/PSR-0 classes
composer dump-autoload --optimize
# or
composer install --optimize-autoloader
# Level 2: Classmap authoritative
# ONLY loads from classmap, skips filesystem checks
composer dump-autoload --classmap-authoritative
# or
composer install --classmap-authoritative
# Level 3: APCu autoloader
# Caches class-to-file map in APCu (requires ext-apcu)
composer dump-autoload --apcu-autoloader
# or
composer install --apcu-autoloader
Сравнение уровней
| Уровень | Скорость | Новые классы | Требования |
|---|---|---|---|
| Без оптимизации | Базовая | Находятся автоматически | Нет |
--optimize |
Быстрая | Находятся через fallback | Нет |
--classmap-authoritative |
Максимальная | НЕ находятся (нужен dump) | Нет |
--apcu |
Очень быстрая | Находятся + кэшируются | ext-apcu |
Конфигурация в composer.json
{
"config": {
"optimize-autoloader": true,
"classmap-authoritative": false,
"apcu-autoloader": false,
"sort-packages": true
}
}
Рекомендация для production:
composer install --no-dev --optimize-autoloader --no-scripts --no-interaction
Conflict и Replace
conflict
Запрещает установку несовместимых пакетов:
{
"conflict": {
"vendor/old-package": "<2.0",
"another/broken-package": "3.1.0"
}
}
Если другой пакет требует vendor/old-package:1.5, Composer выдаст ошибку конфликта.
replace
Объявляет, что ваш пакет заменяет другой. Используется в двух случаях:
1. Форк пакета:
{
"name": "mycompany/monolog-fork",
"replace": {
"monolog/monolog": "3.5.0"
}
}
Теперь все пакеты, которые требуют monolog/monolog, будут удовлетворены вашим форком.
2. Метапакеты и subtree splits:
{
"name": "symfony/symfony",
"replace": {
"symfony/http-kernel": "self.version",
"symfony/http-foundation": "self.version",
"symfony/routing": "self.version"
}
}
Монолитный пакет symfony/symfony заменяет все отдельные компоненты.
Плагины Composer
Плагины расширяют функциональность Composer. Они устанавливаются как обычные пакеты, но имеют тип composer-plugin.
Популярные плагины
{
"require": {
"symfony/flex": "^2.4"
},
"config": {
"allow-plugins": {
"symfony/flex": true,
"phpstan/extension-installer": true
}
}
}
Symfony Flex — автоматическая конфигурация Symfony-бандлов. При установке пакета автоматически создаются конфиг-файлы и регистрируются бандлы.
PHPStan Extension Installer — автоматическое подключение расширений PHPStan.
Безопасность плагинов
С Composer 2.2+ плагины требуют явного разрешения в config.allow-plugins:
{
"config": {
"allow-plugins": {
"symfony/flex": true,
"phpstan/extension-installer": true,
"untrusted/plugin": false
}
}
}
Безопасность: composer audit
Команда composer audit проверяет установленные пакеты на известные уязвимости:
# Check for security vulnerabilities
composer audit
# Output in JSON format (for CI/CD)
composer audit --format=json
# Only check locked packages
composer audit --locked
Пример вывода:
Found 2 security vulnerability advisories affecting 2 packages:
+-------------------+-----------------------------------------------------+
| Package | symfony/http-kernel |
| CVE | CVE-2024-XXXXX |
| Title | Security issue in HTTP kernel |
| Affected versions | >=7.0.0,<7.2.1 |
| Fixed version | 7.2.1 |
+-------------------+-----------------------------------------------------+
Рекомендуется добавлять composer audit в CI/CD пайплайн:
# GitHub Actions example
- name: Security audit
run: composer audit --format=json
composer bump
Команда composer bump обновляет ограничения версий в composer.json до минимальных версий, зафиксированных в composer.lock:
# Before bump:
# composer.json: "monolog/monolog": "^3.0"
# composer.lock: monolog/monolog 3.7.0
composer bump
# After bump:
# composer.json: "monolog/monolog": "^3.7.0"
# composer.lock: monolog/monolog 3.7.0 (unchanged)
# Bump only dev dependencies
composer bump --dev-only
# Dry run (show what would change)
composer bump --dry-run
Это полезно для документирования минимально протестированных версий.
Монорепозиторий с Composer
Монорепозиторий содержит несколько пакетов в одном Git-репозитории.
Структура монорепозитория
monorepo/
├── composer.json # Root composer.json
├── packages/
│ ├── shared-kernel/
│ │ ├── composer.json # Package composer.json
│ │ └── src/
│ │ └── ValueObject/
│ │ └── Email.php
│ ├── auth-service/
│ │ ├── composer.json
│ │ └── src/
│ │ └── AuthService.php
│ └── notification-service/
│ ├── composer.json
│ └── src/
│ └── NotificationService.php
└── app/
├── composer.json
└── src/
Root composer.json
{
"name": "mycompany/monorepo",
"type": "project",
"repositories": [
{
"type": "path",
"url": "packages/*",
"options": {
"symlink": true
}
}
],
"require": {
"mycompany/shared-kernel": "@dev",
"mycompany/auth-service": "@dev",
"mycompany/notification-service": "@dev"
},
"minimum-stability": "dev",
"prefer-stable": true
}
Package composer.json (shared-kernel)
{
"name": "mycompany/shared-kernel",
"description": "Shared domain kernel",
"type": "library",
"require": {
"php": ">=8.4"
},
"autoload": {
"psr-4": {
"MyCompany\\SharedKernel\\": "src/"
}
}
}
Package composer.json (auth-service)
{
"name": "mycompany/auth-service",
"description": "Authentication service",
"type": "library",
"require": {
"php": ">=8.4",
"mycompany/shared-kernel": "^1.0"
},
"autoload": {
"psr-4": {
"MyCompany\\AuthService\\": "src/"
}
}
}
Благодаря symlink: true изменения в пакетах сразу видны без переустановки.
Performance: --prefer-dist vs --prefer-source
# Download zip archives (faster, no .git history)
composer install --prefer-dist
# Clone full git repositories (needed for development)
composer install --prefer-source
# Default behavior:
# - Tagged versions: --prefer-dist
# - Dev versions: --prefer-source
Параллельные загрузки
Composer 2 загружает пакеты параллельно по умолчанию. Можно настроить:
{
"config": {
"process-timeout": 300,
"use-parent-dir": false
}
}
composer.json vs composer.lock в CI/CD
Правильный CI/CD пайплайн
# GitHub Actions
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.4'
extensions: pdo, mbstring, intl, redis
coverage: xdebug
# Cache Composer dependencies
- name: Cache Composer
uses: actions/cache@v4
with:
path: vendor
key: ${{ runner.os }}-composer-${{ hashFiles('composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
# CRITICAL: use install, not update
- name: Install dependencies
run: composer install --no-interaction --prefer-dist --optimize-autoloader
- name: Security audit
run: composer audit
- name: Static analysis
run: vendor/bin/phpstan analyse
- name: Code style
run: vendor/bin/php-cs-fixer fix --dry-run --diff
- name: Tests
run: vendor/bin/phpunit --coverage-clover coverage.xml
deploy:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
# Production install
- name: Install production dependencies
run: composer install --no-dev --optimize-autoloader --no-interaction --no-scripts
- name: Warmup cache
run: php bin/console cache:warmup --env=prod
Создание своего Composer-пакета
Шаг 1: Структура пакета
my-package/
├── composer.json
├── LICENSE
├── README.md
├── src/
│ ├── Calculator.php
│ └── Exception/
│ └── DivisionByZeroException.php
└── tests/
└── CalculatorTest.php
Шаг 2: composer.json пакета
{
"name": "myvendor/calculator",
"description": "A simple calculator library",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "John Doe",
"email": "[email protected]"
}
],
"require": {
"php": ">=8.4"
},
"require-dev": {
"phpunit/phpunit": "^11.5",
"phpstan/phpstan": "^2.1"
},
"autoload": {
"psr-4": {
"MyVendor\\Calculator\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"MyVendor\\Calculator\\Tests\\": "tests/"
}
},
"scripts": {
"test": "phpunit",
"analyse": "phpstan analyse"
},
"minimum-stability": "stable"
}
Шаг 3: Код пакета
<?php
declare(strict_types=1);
namespace MyVendor\Calculator;
use MyVendor\Calculator\Exception\DivisionByZeroException;
/**
* Simple calculator with basic arithmetic operations.
*/
final readonly class Calculator
{
/**
* @param list<float> $history
*/
public function __construct(
private array $history = [],
) {}
public function add(float $a, float $b): float
{
return $a + $b;
}
public function subtract(float $a, float $b): float
{
return $a - $b;
}
public function multiply(float $a, float $b): float
{
return $a * $b;
}
/**
* @throws DivisionByZeroException
*/
public function divide(float $a, float $b): float
{
if ($b === 0.0) {
throw new DivisionByZeroException('Cannot divide by zero');
}
return $a / $b;
}
}
Шаг 4: Публикация на Packagist
# 1. Push to GitHub
# 2. Go to packagist.org/packages/submit
# 3. Enter repository URL
# 4. Configure GitHub webhook for auto-updates
# Tag a version
git tag -a v1.0.0 -m "Release v1.0.0"
git push origin v1.0.0
# Now users can install:
# composer require myvendor/calculator
Продвинутая конфигурация
Полный config блок
{
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
"sort-packages": true,
"allow-plugins": {
"symfony/flex": true
},
"platform": {
"php": "8.4.0"
},
"process-timeout": 300,
"cache-dir": "/tmp/composer-cache",
"vendor-dir": "vendor",
"bin-dir": "vendor/bin",
"discard-changes": false,
"audit": {
"abandoned": "report"
}
}
}
Переменные окружения
# Set Composer home directory
export COMPOSER_HOME=/opt/composer
# Set memory limit for Composer
export COMPOSER_MEMORY_LIMIT=-1
# Set auth token for GitHub
export COMPOSER_AUTH='{"github-oauth": {"github.com": "TOKEN"}}'
# Disable Packagist (for air-gapped environments)
export COMPOSER_DISABLE_NETWORK=1
Аутентификация
# GitHub token (for rate limit)
composer config --global github-oauth.github.com YOUR_TOKEN
# GitLab token
composer config --global gitlab-token.gitlab.com YOUR_TOKEN
# HTTP Basic auth
composer config http-basic.packages.mycompany.com user password
Эти данные сохраняются в ~/.composer/auth.json:
{
"github-oauth": {
"github.com": "ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
},
"http-basic": {
"packages.mycompany.com": {
"username": "user",
"password": "secret"
}
}
}