結論

Composerとは、PHP のライブラリをプロジェクトごとに入れ、使う版をチーム全員でそろえる依存管理ツールです。欲しい範囲を composer.json に書き、実際に入った版を composer.lock に残します。composer install は lock どおりに入れ、composer update は版を決め直して lock を書き換えます。

この記事でわかること

  • init・require・install・update・autoload を実行した出力の原文
  • 新しい版が出た日に install と update で lock がどう変わるかの実物
  • エラー原文12種と、autoload の最適化(-o・-a)の実測

2026年10月29日更新|Composer 2.8.12・PHP 8.3.6・Ubuntu 24.04 で実行確認

Composer の仕事は「どの版を使うか決める」「決めた版を入れる」「クラスを自動で読み込めるようにする」の3つです。最初の2つが update と install に分かれていることを押さえると、ほとんどの迷いが消えます。

flowchart TD
    J[composer.json<br>欲しい範囲 例 ^1.0] --> U[composer update<br>範囲の中から版を決める]
    U --> L[composer.lock<br>決めた版 例 1.1.0]
    L --> I[composer install<br>lock どおりに入れる]
    I --> V[vendor と autoload.php]
    R[composer require] -->|json に追記して| U

よく調べられることの答えを先にまとめます。

知りたいこと 答え 詳しい節
Composerとは PHP のライブラリをプロジェクトごとに入れ、版をそろえるツール Composerとは
Composer のインストール Windows は Composer-Setup.exe、Mac・Linux は公式の4行か Homebrew・apt インストール
composer 使い方(最初の3コマンド) init で composer.json を作り、require で追加し、php で autoload.php を読む init と require
composer install と update の違い install は lock どおりに入れる。update は版を決め直して lock を書き換える install と update の違い
composer.lock は Git に入れるか 入れる。vendor は入れない composer.json と composer.lock
^ と ~ の違い ^1.2.3 は 2.0 未満まで、~1.2.3 は 1.3 未満まで バージョン制約
Class not found になる autoload の設定を変えたら composer dump-autoload を実行する autoload(PSR-4)
Allowed memory size のエラー COMPOSER_MEMORY_LIMIT=-1 を付けて実行する よくあるエラー

確認環境:Ubuntu 24.04.5 LTS の上で、PHP 8.3.6(CLI)と Composer 2.8.12(2025-09-19 版)を実行しました。この環境からは Packagist(repo.packagist.org)への接続がプロキシで止められている(CONNECT 403)ため、Packagist のパッケージは取得していません。代わりに、自作の小さなパッケージ(acme/greeter 1.0.0・1.1.0・2.0.0 など)を zip にして artifact リポジトリ・path リポジトリ・127.0.0.1 で動かした composer 型リポジトリ(php -S)から配り、init・require・install・update・remove・show・outdated・why・why-not・validate・audit・dump-autoload・check-platform-reqs と、Git のブランチをまたいだ composer.lock の衝突を実際に動かしています。HOME・COMPOSER_HOME・キャッシュは作業用の一時ディレクトリに向け、作業はすべて root のコンテナの中です。autoload の速さは、2,000個のクラスを生成して php -S(OPcache 有効)と CLI で測りました。Windows と Mac のインストール手順、最新版の番号、各コマンドの仕様は getcomposer.org の公式ドキュメントで確かめた範囲だけを書いています。図は mermaid で描画を確かめました(確認日 2026年10月29日)。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Composerとは?使い方とinstall・updateの違いを実行して解説」

Composerとは(PHPのパッケージ管理・依存管理ツール)

この節では、Composer が何をする道具で、使わない場合と何が違うのかが分かります。

PHP でメール送信・ログ出力・HTTP 通信などを自分で一から書かず、公開されているライブラリを使うことはよくあります。ライブラリはさらに別のライブラリを使っていることが多く、手で zip を落として置くやり方では「どれが何を必要としているか」「どの版を使っているか」がすぐに分からなくなります。Composer はこれを、設定ファイル1つとコマンドで管理します。

公式ドキュメントは Composer を「Yum や Apt のようなパッケージマネージャーではなく、依存関係をプロジェクトごとに管理するツール」と説明しています。入れたライブラリはプロジェクトの中の vendor フォルダーに置かれ、既定ではパソコン全体には入りません。考え方は Node.js の npm、Ruby の bundler を参考にしていると書かれています。

1版を決める

composer.json の「^1.0 なら何でもよい」という範囲から、他のライブラリの条件とぶつからない版を自動で選ぶ。

2決めた版を記録して入れる

選んだ版を composer.lock に書き、vendor に展開する。lock があれば、誰がいつ入れても同じ版になる。

3クラスを自動で読み込む

vendor/autoload.php を1回 require すれば、ライブラリと自分のクラスを include なしで使える。

パッケージの公開場所は、既定では Packagist(packagist.org)です。composer require monolog/monolog のように「ベンダー名/パッケージ名」で指定すると、Packagist から情報を取ってきます。社内のライブラリは、Git リポジトリや手元のフォルダー(path)を repositories に書けば同じ手順で扱えます。この記事の実行例は、この仕組みを使って手元のリポジトリから配っています。

Laravel・Symfony・CakePHP などのフレームワークは、プロジェクトの作成から Composer を前提にしています。WordPress でもプラグイン開発やテーマで使われることがあります。PHP で仕事をするなら、最初に覚える道具の1つです。

Composerのインストール(Windows・Mac・Linux)

この節では、OS ごとのインストール方法と、入ったことの確かめ方が分かります。

Composer 本体は composer.phar という1つの PHP ファイルです。動かすには PHP が先に入っている必要があります。公式ドキュメントでは、最新版は PHP 7.2.5 以上で動き、それより前の PHP(5.3.2〜7.1)では LTS の 2.2 系を使うよう案内しています。2026年10月29日時点で、公式ダウンロードページに載っている最新の安定版は 2.11.0、LTS は 2.2.31 です。

OS 入れ方(公式の案内) 注意
Windows Composer-Setup.exe を実行する。最新版が入り、PATH も設定される 入れたあとはターミナルを開き直す(公式の注意)
Mac 公式の4行のコマンドで composer.phar を作り、/usr/local/bin/composer に移す。Homebrew の brew install composer でも入る macOS の版によっては /usr/local/bin が無いので mkdir -p で作る(公式の注意)
Linux 公式の4行のコマンド。Ubuntu などは apt の composer パッケージもある apt の版は遅れることがある(Ubuntu 24.04 の候補は 2.7.1)
Docker PHP のイメージに composer.phar を入れて使う root で動かす前提なら COMPOSER_ALLOW_SUPERUSER=1

コマンドラインでのインストールは、公式ダウンロードページの次の4行です。2行目のハッシュ値は新しい版のインストーラーが出るたびに変わるため、必ず公式ページからその日の4行をそのまま写します(ここでは値を省いています)。

php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('sha384', 'composer-setup.php') === '(公式ページに載っている値)') { echo 'Installer verified'.PHP_EOL; } else { echo 'Installer corrupt'.PHP_EOL; unlink('composer-setup.php'); exit(1); }"
php composer-setup.php
php -r "unlink('composer-setup.php');"

# どこからでも composer で呼べるようにする(Mac・Linux)
sudo mv composer.phar /usr/local/bin/composer

2行目は、落としてきたインストーラーが改ざんされていないかを SHA-384 で照合しています。一致しないと「Installer corrupt」と出て、ファイルを消して終わります。

入ったことは composer --version で確かめます。この環境では次のように出ました。root で動かしたので、先頭に警告が付いています。

$ composer --version
Composer plugins have been disabled for safety in this non-interactive session.
Set COMPOSER_ALLOW_SUPERUSER=1 if you want to allow plugins to run as root/super user.
Do not run Composer as root/super user! See https://getcomposer.org/root for details
Composer version 2.8.12 2025-09-19 13:41:59
PHP version 8.3.6 (/usr/bin/php8.3)
Run the "diagnose" command to get more detailed diagnostics output.

「Do not run Composer as root」は、ライブラリに含まれるスクリプトやプラグインが root の権限で動くことへの警告です。普段の開発では一般ユーザーで実行し、sudo composer は使いません。公式ドキュメントによると、COMPOSER_ALLOW_SUPERUSER=1 はこの警告を止める環境変数で、Docker のように常に root で動く環境を想定したものです。

Composer 本体の更新は composer self-update、前の版に戻すのは composer self-update --rollback です。apt や Homebrew で入れた場合は、それぞれのパッケージ管理で更新します。

composer init と require の使い方(最初のプロジェクト)

この節では、空のフォルダーから composer.json を作り、ライブラリを追加して使うまでの流れが分かります。

1

composer init で composer.json を作る

対話で名前・説明・作者・ライセンスなどを聞かれる。-n を付けると聞かずに最小の形で作る。

composer.json ができる

2

composer require でライブラリを足す

composer.json に追記し、版を決めて lock を書き、vendor に入れる。版を省くと最新の安定版から ^ の範囲が自動で付く。

composer.lock と vendor ができる

3

開発だけで使うものは --dev で足す

テストツールなどは composer require --dev で require-dev に入れる。本番では --no-dev で外せる。

require-dev に入る

4

vendor/autoload.php を読み込んで使う

PHP ファイルの先頭で1回 require すれば、ライブラリのクラスを名前空間つきの名前で呼べる。

php index.php で動く

composer init -n を実行すると、次の composer.json ができました。

$ composer init --name=rjc/demo --type=project -n
Writing ./composer.json

$ cat composer.json
{
    "name": "rjc/demo",
    "type": "project",
    "require": {}
}

次に、自作のライブラリ acme/logger(中で acme/greeter を使う)を require しました。指定したのは1つですが、acme/logger が必要とする acme/greeter も自動で入っています。これが「依存関係の解決」です。

$ composer require acme/logger
./composer.json has been updated
Running composer update acme/logger
Loading composer repositories with package information
Updating dependencies
Lock file operations: 2 installs, 0 updates, 0 removals
  - Locking acme/greeter (1.0.0)
  - Locking acme/logger (1.0.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 2 installs, 0 updates, 0 removals
  - Downloading acme/greeter (1.0.0)
  - Downloading acme/logger (1.0.0)
  - Installing acme/greeter (1.0.0): Extracting archive
  - Installing acme/logger (1.0.0): Extracting archive
Generating autoload files
No security vulnerability advisories found.
Using version ^1.0 for acme/logger

出力の2行目「Running composer update acme/logger」のとおり、require は「composer.json に1行足して、そのパッケージだけ update する」コマンドです。続けて composer require --dev acme/testkit を実行すると、composer.json は次の形になりました。

{
    "name": "rjc/demo",
    "type": "project",
    "require": {
        "php": ">=8.1",
        "acme/logger": "^1.0"
    },
    "autoload": {
        "psr-4": { "App\\": "src/" }
    },
    "require-dev": {
        "acme/testkit": "^1.0"
    }
}

使う側のコードは次のとおりです。require __DIR__ . '/vendor/autoload.php'; の1行だけで、vendor の中のクラスも src の中の自分のクラスも読み込めます。

<?php
// src/Greeting.php
namespace App;

use Acme\Logger\Hello as LoggerHello;
use Acme\Greeter\Hello as GreeterHello;

final class Greeting
{
    public function run(): string
    {
        return GreeterHello::say() . ' / ' . LoggerHello::say();
    }
}
<?php
// index.php
require __DIR__ . '/vendor/autoload.php';

echo (new App\Greeting())->run(), PHP_EOL;
$ php index.php
greeter 1.0.0 / logger 1.0.0

Packagist のライブラリでも手順は同じです。たとえばログのライブラリ Monolog なら composer require monolog/monolog です。この環境では Packagist への接続が止められているため、実行すると次のエラーになり、composer.json は元のままでした(失敗すると変更を戻す動きです)。

$ composer require monolog/monolog

In CurlDownloader.php line 394:

  curl error 56 while downloading https://repo.packagist.org/packages.json: C
  ONNECT tunnel failed, response 403

会社のネットワークでこの形のエラーが出たら、プロキシの設定(環境変数 HTTPS_PROXY)と、Packagist への接続が許可されているかを、ネットワークの担当者に確かめます。

composer.json と composer.lock・vendor の役割

この節では、Composer が作る3つのものが何を持っていて、どれを Git に入れるのかが分かります。

composer.json(人が書く・希望)

「acme/logger を ^1.0 の範囲で」という条件

autoload・scripts・リポジトリの設定

Git に入れる

composer.lock(Composer が書く・結果)

「acme/greeter は 1.1.0、zip の shasum はこれ」という確定値

依存の依存まで全部の版が載る

Git に入れる

vendor は Git に入れません。公式ドキュメントは .gitignore に vendor を足すよう案内しています。lock があれば composer install で同じ中身を作り直せるからです。一方 composer.lock は「プロジェクトを準備する全員が同じ版を使うために重要」として、コミットするよう書かれています。公式ドキュメントでは、ライブラリ(他の人に使われるパッケージ)も lock をコミットするよう案内しています。ただし、ライブラリの lock は開発とテストの版をそろえるためのもので、そのライブラリを使う側のプロジェクトでは読まれません。

実際の composer.lock の中身(最初のパッケージの部分)です。キーは _readme・content-hash・packages・packages-dev・platform など12個ありました。

{
    "content-hash": "08e903ecf32fea1d04a10adb07072530",
    "packages": [
        {
            "name": "acme/greeter",
            "version": "1.0.0",
            "dist": {
                "type": "zip",
                "url": "/srv/s4/r17/t173/artifacts/acme-greeter-1.0.0.zip",
                "shasum": "21fd6f9df2990b348a4a42d675e660db8a4fe130"
            },
            "require": { "php": ">=8.1" },
            "autoload": { "psr-4": { "Acme\\Greeter\\": "src/" } }
        }
    ]
}

content-hash は composer.json の中身から作られる値です。composer.json を手で書き換えて lock と合わなくなると、install の時に警告が出ます(エラーの節で原文を載せています)。

vendor の中は次のようになっていました。vendor/composer/ の中にあるのが autoload の仕組みで、autoload_psr4.php に「名前空間 → フォルダー」の対応表が書かれます。

vendor/autoload.php
vendor/acme/greeter/   vendor/acme/logger/   vendor/acme/testkit/
vendor/composer/ClassLoader.php
vendor/composer/autoload_psr4.php
vendor/composer/autoload_classmap.php
vendor/composer/autoload_static.php
vendor/composer/installed.json
vendor/composer/platform_check.php
// vendor/composer/autoload_psr4.php(Composer が作ったもの)
return array(
    'App\\' => array($baseDir . '/src'),
    'Acme\\Testkit\\' => array($vendorDir . '/acme/testkit/src'),
    'Acme\\Logger\\' => array($vendorDir . '/acme/logger/src'),
    'Acme\\Greeter\\' => array($vendorDir . '/acme/greeter/src'),
);

vendor の扱い

やってはいけないvendor の中のファイルを直接書き換える。次の install・update で上書きされて消える
→
代わりに直したいライブラリは fork して repositories に足すか、path リポジトリで手元の版を使う(後の節)

vendor は「いつでも作り直せる置き場」として扱う

composer install と update の違い(実際に比べた結果)

この節では、install と update の違いを、新しい版が出た日に両方を実行した結果で確かめられます。

acme/greeter 1.0.0 を lock に記録してコミットしたあと、リポジトリに 1.1.0 と 2.0.0 を追加しました。acme/logger は acme/greeter を ^1.0 で求めています。この状態で vendor を消して composer install を実行します。

$ rm -rf vendor && composer install
Installing dependencies from lock file (including require-dev)
Verifying lock file contents can be installed on current platform.
Package operations: 3 installs, 0 updates, 0 removals
  - Installing acme/greeter (1.0.0): Extracting archive
  - Installing acme/logger (1.0.0): Extracting archive
  - Installing acme/testkit (1.0.0): Extracting archive
Generating autoload files

$ php index.php
greeter 1.0.0 / logger 1.0.0
$ git status --short
(何も出ない=composer.lock は変わっていない)

1.1.0 が出ていても、install は lock に書かれた 1.0.0 を入れました。出力の1行目「from lock file」がその印で、リポジトリの一覧を読みに行く「Loading composer repositories」の行もありません。次に、更新できるものを composer outdated で見ます。

$ composer outdated -D
All your direct dependencies are up to date

$ composer outdated
Legend:
! patch or minor release available - update recommended
~ major release available - update possible

Direct dependencies required in composer.json:
Everything up to date

Transitive dependencies not required in composer.json:
acme/greeter 1.0.0 ~ 2.0.0 local demo package acme/greeter

acme/greeter は自分で直接 require していない「依存の依存」なので、-D(直接の依存だけ)では出ません。--dry-run で update の結果を先に見てから、本当に update します。

$ composer update
Loading composer repositories with package information
Updating dependencies
Lock file operations: 0 installs, 1 update, 0 removals
  - Upgrading acme/greeter (1.0.0 => 1.1.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 0 installs, 1 update, 0 removals
  - Downloading acme/greeter (1.1.0)
  - Upgrading acme/greeter (1.0.0 => 1.1.0): Extracting archive
Generating autoload files
No security vulnerability advisories found.

$ php index.php
greeter 1.1.0 / logger 1.0.0
$ git diff --stat
 composer.lock | 6 +++---

update は 1.1.0 に上げ、composer.lock を書き換えました(版・zip の URL・shasum の3行)。2.0.0 が出ているのに 1.1.0 で止まったのは、acme/logger が ^1.0 を求めているからです。update は「範囲の中の最新」を選ぶのであって、「出ている中の最新」を選ぶわけではありません。

225mscomposer installvendor を消して5回の平均。キャッシュあり
525mscomposer update同じ条件。版を決める処理が加わる
6行update で変わった lock追加3行・削除3行。install では0行

パッケージ4つの小さな例でも、update は install の約2.3倍かかりました。パッケージが数十〜百を超えるプロジェクトでは、版を決める処理(依存の解決)の分だけ差が大きくなります。

コマンド composer.json composer.lock vendor
composer install 読むだけ 読むだけ(無いときだけ作る) lock どおりに作る
composer update 読むだけ 版を決め直して書き換える 新しい lock に合わせる
composer update acme/greeter 読むだけ 指定したものだけ書き換える 指定したものだけ変わる
composer require 名前 1行足す 足したものだけ書き換える 足したものが入る
composer remove 名前 1行消す 消したものを除く 消したものが消える

lock が無いフォルダーで composer install を実行すると、次のメッセージが出て、中では update と同じ処理が走りました。公式ドキュメントも、最初の1回は update を使うと書いています。

No composer.lock file present. Updating dependencies to latest instead of installing from lock file. See https://getcomposer.org/install for more information.

どちらを使うかの判断表

  1. 1git clone した直後・git pull で lock が変わった → composer install他の人が決めた版をそのまま入れる
  2. 2本番・CI・Docker イメージ作成 → composer install --no-devupdate は使わない。テストした版と違う版が入るため
  3. 3ライブラリを1つ足したい → composer requirecomposer.json を手で書き換えない
  4. 41つだけ新しくしたい → composer update ベンダー/名前影響を小さくできる。-W で依存も一緒に動かせる
  5. 5全部を範囲内の最新にしたい → composer updateブランチを切って実行し、テストしてから lock をコミット
  6. 6結果だけ先に見たい → composer update --dry-runlock も vendor も変えない

バージョン制約の書き方(^ と ~ の違い)

この節では、composer.json の版の書き方と、それぞれがどの版を許すのかが、実際に判定した結果で分かります。

Composer 本体に入っている判定ライブラリ(composer/semver)に、8つの版を渡して、どれが条件に合うかを判定させました。

<?php
require 'phar:///dev/shm/t173/composer.phar/vendor/autoload.php';
use Composer\Semver\Semver;

$versions = ['1.2.2','1.2.3','1.2.9','1.3.0','1.9.0','2.0.0','0.3.5','0.4.0'];
foreach (['1.2.3','^1.2.3','~1.2.3','~1.2','1.2.*','>=1.2 <2.0','^0.3','*'] as $c) {
    printf("%-12s => %s\n", $c, implode(', ', Semver::satisfiedBy($versions, $c)));
}
1.2.3        => 1.2.3
^1.2.3       => 1.2.3, 1.2.9, 1.3.0, 1.9.0
~1.2.3       => 1.2.3, 1.2.9
~1.2         => 1.2.2, 1.2.3, 1.2.9, 1.3.0, 1.9.0
1.2.*        => 1.2.2, 1.2.3, 1.2.9
>=1.2 <2.0   => 1.2.2, 1.2.3, 1.2.9, 1.3.0, 1.9.0
^0.3         => 0.3.5
*            => 1.2.2, 1.2.3, 1.2.9, 1.3.0, 1.9.0, 2.0.0, 0.3.5, 0.4.0
書き方 意味 許す範囲
1.2.3 その版だけ 1.2.3
^1.2.3(キャレット) 互換が保たれる範囲。require の既定 1.2.3 以上 2.0.0 未満
~1.2.3(チルダ) 最後の桁だけ上げてよい 1.2.3 以上 1.3.0 未満
~1.2 同じく最後の桁(ここでは2桁目)を上げてよい 1.2 以上 2.0 未満
1.2.*(ワイルドカード) 1.2 系なら何でも 1.2.0 以上 1.3.0 未満
>=1.2 <2.0 範囲を直接書く(空白は「かつ」、|| は「または」) 書いたとおり
^0.3 0.x は小さい桁でも互換が壊れうるので狭い 0.3.0 以上 0.4.0 未満

迷ったら、composer require が自動で付ける ^ のままにします。~1.2 と ~1.2.3 は書く桁数で意味が変わるので、読み違えやすい点に注意します。また、版の付いていない Git のブランチなどは「dev」扱いで、既定(minimum-stability が stable)では入りません(エラーの節で原文を載せています)。

autoload(PSR-4)の使い方と composer dump-autoload

この節では、自分のクラスを Composer の autoload で読み込む書き方と、Class not found になる3つの原因が分かります。

composer.json の autoload.psr-4 に「名前空間の先頭 → フォルダー」を書くと、App\Greeting は src/Greeting.php、App\Mail\Sender は src/Mail/Sender.php から読まれます。名前空間とフォルダーの対応の考え方そのものは、関連記事「PHP namespaceとuseの使い方|名前空間とPSR-4を図解」で図にしています。この記事では、Composer 側で起きることを実物で見ます。

"autoload": {
    "psr-4": {
        "App\\": "src/",
        "Rjc\\Util\\": "lib/"
    }
},
"autoload-dev": {
    "psr-4": { "Tests\\": "tests/" }
}

lib/Tax.php に Rjc\Util\Tax クラスを置き、composer.json に "Rjc\\Util\\": "lib/" を足しただけで実行すると、次のエラーになりました。

$ php tax.php
PHP Fatal error:  Uncaught Error: Class "Rjc\Util\Tax" not found in /srv/s4/r17/t173/p1/tax.php:3
Stack trace:
#0 {main}
  thrown in /srv/s4/r17/t173/p1/tax.php on line 3

$ composer dump-autoload
Generating autoload files
Generated autoload files

$ php tax.php
1100

autoload の設定は composer.json を書き換えただけでは効かず、composer dump-autoload で vendor/composer の対応表を作り直して初めて効きます。install・update・require でも作り直されます。

  • 1autoload を変えたら dump-autoload上の実行例のとおり、しないと Class not found のまま
  • 2ファイル名とクラス名の大文字・小文字をそろえるTax.php を tax.php に変えると Linux では Class not found になった。Windows・Mac では動いてしまうので、本番の Linux で初めて落ちる
  • 3namespace 宣言とフォルダーの位置を合わせるずれていると dump-autoload -o が警告を出して、そのクラスを飛ばす
  • 4JSON の中では \ を2つ重ねる"App\\" と書く。"App\" だと JSON の書き方の誤りになる

3番目の警告は、src/Sub/Foo.php に namespace App\Wrong; と書いたときに次のように出ました。

$ composer dump-autoload -o
Generating optimized autoload files
Class App\Wrong\Foo located in ./src/Sub/Foo.php does not comply with psr-4 autoloading standard (rule: App\ => ./src). Skipping.
Generated optimized autoload files containing 6 classes

関数だけのファイル(helpers.php など)はクラスではないので PSR-4 では読まれません。"files": ["src/helpers.php"] に書くと、autoload.php を読んだ時点で毎回読み込まれます。include と require の違いそのものは、関連記事「PHP include・requireの違い|require_onceと相対パス」で扱っています。

本番環境での composer install(--no-dev・-o・-a の実測)

この節では、本番サーバーやコンテナに入れるときのオプションと、autoload の最適化でどれだけ速くなるかの実測が分かります。

$ composer install --no-dev --optimize-autoloader
Installing dependencies from lock file
Verifying lock file contents can be installed on current platform.
Package operations: 2 installs, 0 updates, 0 removals
  - Installing acme/greeter (1.1.0): Extracting archive
  - Installing acme/logger (1.0.0): Extracting archive
Generating optimized autoload files

--no-dev で require-dev の acme/testkit が入らず、「(including require-dev)」の文字も消えました。--optimize-autoloader(-o)は、PSR-4 の「フォルダーを探しに行く」読み込みを、全クラスの一覧表(classmap)に変えます。公式ドキュメントは本番で使うことを勧めていますが、既定では行われません。

どれだけ違うかを、src/Gen/ に2,000個のクラスを作って測りました。php -S(OPcache 有効)で同じページを30回開いた平均です(最初の5回は捨てています)。

autoload の作り方 autoload.php の読み込み 2,000クラスを読む 存在しないクラスを2万回探す
既定(dump-autoload) 0.07ms 6.05ms 41.94ms
-o(classmap に変換) 0.79ms 1.07ms 36.74ms
-a(classmap だけを見る) 0.09ms 1.11ms 5.86ms

2,000クラスの読み込みは -o で 6.05ms から 1.07ms に、約5.7分の1になりました。-a(--classmap-authoritative)は「一覧表に無いクラスはフォルダーを探さない」ので、class_exists で存在しないクラスを調べるような処理が約7分の1になっています。そのかわり、-a のあとに追加したクラスは dump-autoload し直すまで見つかりません。開発中は既定のまま、本番のビルドで -o か -a を付けるのが安全です。

同じ計測を OPcache なしの CLI(php bench.php を5回)で行うと、2,000クラスの読み込みは既定 19.57ms・-o 17.83ms・-a 16.44ms で、差はほとんど出ませんでした。classmap 自体(今回は 114,328 バイトの PHP ファイル)を毎回読み直すためです。-o の効果は OPcache の効く Web サーバーで出るので、CLI だけで測って「効果が無い」と判断しないようにします。

本番に入れる前には、サーバーの PHP と拡張が足りているかを composer check-platform-reqs で確かめられます。公式ドキュメントによると、このコマンドは composer.json の config.platform の設定を無視して、実際の環境を調べます。

$ composer check-platform-reqs
Checking platform requirements for packages in the vendor dir
php 8.3.6 acme/modern requires php (>= 8.4.0.0-dev) acme/modern requires php (>=8.4) failed

これは、PHP 8.4 以上が必要な acme/modern を --ignore-platform-req=php で無理に入れた状態です。このとき php index.php はエラーなく動いてしまいました。無視のオプションで入れたものは、実行して初めて壊れるので、本番の手順に check-platform-reqs を入れておくと見つけられます。

composer のよく使うコマンド一覧

この節では、install・update 以外によく使うコマンドと、その出力が分かります。

コマンド すること よく使う形
composer show 入っているパッケージの一覧 show -t(木の形)・show 名前(詳細)
composer outdated 新しい版があるものの一覧 outdated -D(直接の依存だけ)
composer why そのパッケージを誰が必要としているか why acme/greeter
composer why-not その版に上げられない理由 why-not acme/greeter 2.0.0
composer remove パッケージを外す remove 名前・remove --dev 名前
composer validate composer.json の書き方を検査 validate --no-check-publish
composer audit 脆弱性情報と照らし合わせる audit(既定は Packagist の情報)
composer run scripts に書いたコマンドを実行 run test・run hello
composer create-project パッケージを雛形にして新しいプロジェクトを作る フレームワークの新規作成で使う

依存の木と、上げられない理由の調べ方です。前の節で 2.0.0 に上がらなかった理由が、why-not で1行で分かります。

$ composer show -t
acme/logger 1.0.0 local demo package acme/logger
|--acme/greeter ^1.0
|  `--php >=8.1
`--php >=8.1
acme/testkit 1.0.0 local demo package acme/testkit
`--php >=8.1

$ composer why acme/greeter
acme/logger 1.0.0 requires acme/greeter (^1.0)

$ composer why-not acme/greeter 2.0.0
acme/logger 1.0.0 requires acme/greeter (^1.0)
Not finding what you were looking for? Try calling `composer update "acme/greeter:2.0.0" --dry-run` to get another view on the problem.

scripts でよく使う作業を登録する

composer.json の scripts に書いたコマンドは composer run 名前 で動き、post-install-cmd のような決まった名前に書くと、install のあとに自動で動きます。npm の scripts と同じ考え方です。

"scripts": {
    "hello": "php -r \"require 'vendor/autoload.php'; echo Rjc\\MyLib\\Version::V, PHP_EOL;\"",
    "post-install-cmd": ["@hello"]
}
$ composer install
Installing dependencies from lock file (including require-dev)
Verifying lock file contents can be installed on current platform.
Nothing to install, update or remove
Generating autoload files
> php -r "require 'vendor/autoload.php'; echo Rjc\MyLib\Version::V, PHP_EOL;"
edit-2

composer audit の結果の読み方

Composer 2.4 以降は、update・require のあとに自動で脆弱性の確認が走り、「No security vulnerability advisories found.」と出ます。この環境では Packagist への接続を止めた状態でも同じ文が出ました。手元のリポジトリだけを使う設定では照らし合わせる情報源がないため、「見つからなかった」は「安全が確かめられた」という意味になりません。composer diagnose を実行すると、接続できていないことが分かります。

$ composer diagnose
Checking composer.json: WARNING
No license specified, it is recommended to do so. For closed-source software you may use "proprietary" as license.
Checking composer.lock: OK
Checking platform settings: OK
Checking git settings: OK git version 2.43.0
Checking http connectivity to packagist: FAIL
Checking https connectivity to packagist: FAIL
Checking HTTP proxy with https: FAIL
Checking Composer and its dependencies for vulnerabilities: Failed performing audit: curl error 56 while downloading https://repo.packagist.org/packages.json: CONNECT tunnel failed, response 403

社内ライブラリを使う(path・artifact・composer リポジトリ)

この節では、Packagist に公開していないライブラリを Composer で扱う3つの方法と、そのときに出るエラーが分かります。

repositories の type 置き場所 向いている場面
path 手元のフォルダー(既定はシンボリックリンク) アプリとライブラリを同時に直す開発中
vcs Git リポジトリ(タグが版になる) 社内の Git サーバーで管理しているライブラリ
artifact zip を並べたフォルダー ネットワークに出られない環境への持ち込み
composer packages.json を返す HTTP サーバー 社内向けの Packagist(Satis・Private Packagist など)

path リポジトリでは、vendor の中がシンボリックリンクになりました。ライブラリ側のファイルを直すと、install し直さなくてもすぐ反映されます。

{
    "require": { "rjc/mylib": "@dev" },
    "repositories": [
        { "type": "path", "url": "../packages/mylib" }
    ]
}
$ composer update
  - Locking rjc/mylib (dev-main)
  - Installing rjc/mylib (dev-main): Symlinking from ../packages/mylib

$ ls -l vendor/rjc/
lrwxrwxrwx 1 root root 24 Oct 31 08:08 mylib -> ../../../packages/mylib/

最初は "rjc/mylib": "*" と書いて、次のエラーになりました。path のライブラリは版が無いので「dev-main」という開発版として扱われ、既定の minimum-stability(stable)では選ばれません。@dev を付けると、そのパッケージだけ開発版を許せます。

Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Root composer.json requires rjc/mylib *, found rjc/mylib[dev-main] but it does not match your minimum-stability.

127.0.0.1 の HTTP サーバーを composer 型のリポジトリにすると、次のように断られました。Composer は既定で http(暗号化なし)の接続を許しません。

In Config.php line 618:

  Your configuration does not allow connections to http://127.0.0.1:18174/pac
  kages.json. See https://getcomposer.org/doc/06-config.md#secure-http for de
  tails.

composer config secure-http false で通りますが、毎回「Warning: Accessing 127.0.0.1 over http which is an insecure protocol.」と出ます。手元の検証以外では secure-http を切らず、社内のリポジトリにも https を用意するのが基本です。

サーバーが止まっていても install できるか

リポジトリのサーバーを止めて試すと、キャッシュ(COMPOSER_CACHE_DIR)に zip が残っている間は install が成功しました。composer clear-cache でキャッシュを消すと、次のように失敗しました。CI でキャッシュを使うと速くなるのはこのためです。

$ composer install
  - Downloading acme/greeter (1.1.0)

In CurlDownloader.php line 394:

  curl error 7 while downloading http://127.0.0.1:18174/dist/acme-greeter-1.1
  .0.zip: Failed to connect to 127.0.0.1 port 18174 after 0 ms: Couldn't conn
  ect to server

composer.lock がコンフリクトしたとき(Git のマージ)

この節では、2つのブランチがそれぞれライブラリを足したときに起きる composer.lock の衝突と、その直し方が分かります。

ブランチ feat-a で acme/mailer を、feat-b で acme/cache を require し、feat-b に feat-a をマージしました。

$ git merge feat-a
Auto-merging composer.lock
CONFLICT (content): Merge conflict in composer.lock
Automatic merge failed; fix conflicts and then commit the result.

$ grep -n -A3 '<<<<<<<' composer.lock
7:<<<<<<< HEAD
8-    "content-hash": "d5a17a93e6fec80db00f416a12328285",
9-=======
10-    "content-hash": "8e8101b506e932310f9755b73cc5d5b9",

composer.json も衝突していて、そのまま Composer を動かすと JSON として読めずに止まりました。

In JsonFile.php line 381:

  "./composer.json" does not contain valid JSON
  Parse error on line 6:
  ...me/logger": "^1.0",<<<<<<< HEAD
  ---------------------^
  Expected: 'STRING' - It appears you have an extra trailing comma
1

composer.json は手で両方を残す

acme/cache と acme/mailer の2行を両方残し、衝突の印(<<<<<<< など)を消す。

人が直す

2

composer.lock は片方を採る

git checkout --ours composer.lock で今のブランチ側(acme/cache 入り)を採る。lock を手で混ぜない。

lock を手で編集しない

3

もう片方のパッケージだけ update する

composer update acme/mailer で、足りない1つだけ lock に足す。全体の update はしない。

他の版は動かさない

4

validate してからコミット

composer validate で lock と json が合っているかを見て、2つのファイルを一緒にコミットする。

マージ完了

手順2のあとに install すると「Required package "acme/mailer" is not present in the lock file.」と警告が出て、手順3の update で「Locking acme/mailer (1.0.0)」と1つだけ足されました。公式ドキュメント(Resolving merge conflicts)には、変更の多いブランチの composer.json と composer.lock を採ってもう一方の変更を composer require で入れ直す方法と、lock に足りないパッケージを composer update ベンダー/名前 で足す方法が載っています。マージのあとは composer validate と composer install --dry-run で確かめるよう案内されています。

composer のよくあるエラーと直し方(原文つき)

この節では、Composer でよく出るエラーの原文と、症状から原因と直し方を引ける表が分かります。表の原文は、すべてこの環境で実際に出たものです。

症状(原文の要点) 原因 直し方
Your requirements could not be resolved to an installable set of packages.(conflicts with another require) 他のパッケージが求める範囲とぶつかる why-not で原因を見て、-W を付けるか、相手のパッケージも上げる
requires php >=8.4 which does not match your installed version 8.3.6 PHP の版が足りない PHP を上げるか、対応する前の版を指定する
requires ext-imagick * but it is not present PHP の拡張が入っていない 拡張を入れる(php -m で確かめる)
Allowed memory size of 12582912 bytes exhausted PHP のメモリ上限に当たった COMPOSER_MEMORY_LIMIT=-1 composer update
The lock file is not up to date with the latest changes in composer.json composer.json を手で書き換えた・マージで食い違った composer update 名前 で lock を合わせる
does not match your minimum-stability 版の無い開発版を指定した "@dev" を付けるか、タグを打って版を付ける
Could not find a matching version of package 名前の綴り・リポジトリの指定違い Packagist か repositories で正しい名前を確かめる
Class "..." not found dump-autoload していない・大文字小文字・namespace 違い autoload の節のチェックリスト
does not comply with psr-4 autoloading standard namespace とフォルダーの位置が合わない namespace かファイルの置き場所を直す
Your configuration does not allow connections to http:// http のリポジトリは既定で拒否 リポジトリを https にする
curl error 56 ... CONNECT tunnel failed, response 403 プロキシが Packagist への接続を止めている プロキシの設定と許可をネットワーク担当に確かめる
does not contain valid JSON composer.json の書き間違い・衝突の印が残っている エラーの行を直し、composer validate

PHP の版・拡張が足りないとき

PHP 8.4 以上を求めるパッケージと、imagick 拡張を求めるパッケージを require すると、次のように出ました。

$ composer require acme/modern
Cannot use acme/modern's latest version 1.0.0 as it requires php >=8.4 which is not satisfied by your platform.

In PackageDiscoveryTrait.php line 325:

  Package acme/modern has requirements incompatible with your PHP version, PH
  P extensions and Composer version:
    - acme/modern 1.0.0 requires php >=8.4 which does not match your installe
  d version 8.3.6.

$ composer require acme/imaging
Cannot use acme/imaging's latest version 1.0.0 as it requires ext-imagick * which is missing from your platform.

開発機と本番で PHP の版が違うときは、composer.json の "config": {"platform": {"php": "8.2.0"}} で「本番の版」を Composer に教えておくと、本番で動かない版を選ばなくなります。--ignore-platform-reqs は条件を見ないで入れるオプションで、前の節のとおり実行時に初めて壊れます。

範囲がぶつかるとき

acme/logger が ^1.0 を求めている状態で composer require acme/greeter:^2.0 を実行した結果です。終了コードは 2 で、composer.json と composer.lock は元に戻りました。

Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Root composer.json requires acme/greeter ^2.0, found acme/greeter[2.0.0] but these were not loaded, likely because it conflicts with another require.
  Problem 2
    - acme/logger is locked to version 1.0.0 and an update of this package was not requested.
    - acme/logger 1.0.0 requires acme/greeter ^1.0 -> found acme/greeter[1.0.0, 1.1.0] but it conflicts with your root composer.json require (^2.0).

Use the option --with-all-dependencies (-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions.

Installation failed, reverting ./composer.json and ./composer.lock to their original content.

Problem は下から読むと分かりやすく、「acme/logger 1.0.0 が ^1.0 を求めている」のが本当の原因です。-W を付けても、acme/logger に acme/greeter 2.0 対応の版が無ければ解決しません。

メモリが足りないとき

公式ドキュメントによると、Composer は自分で memory_limit を 1.5G まで引き上げます。それでも足りないときや、上限を小さく指定したときは次のエラーになります(ここでは COMPOSER_MEMORY_LIMIT=12M で再現しました)。

PHP Fatal error:  Allowed memory size of 12582912 bytes exhausted (tried to allocate 2097152 bytes) in phar:///usr/local/bin/composer/vendor/composer/ClassLoader.php on line 576

Check https://getcomposer.org/doc/articles/troubleshooting.md#memory-limit-errors for more info on how to handle out of memory errors.
# 公式ドキュメントにある2つの方法
COMPOSER_MEMORY_LIMIT=-1 composer update
php -d memory_limit=-1 /usr/local/bin/composer update

update は依存の解決でメモリを多く使い、install はほとんど使いません。本番サーバーでメモリ不足が出る場合は、本番で update を実行していないかを見直します。

npm・pip との違い(対応表)

この節では、他の言語のパッケージ管理を知っている人向けに、Composer のコマンドとファイルの対応が分かります。

やること Composer(PHP) npm(Node.js) pip(Python)
設定ファイル composer.json package.json requirements.txt・pyproject.toml
版の記録 composer.lock package-lock.json 標準では無い(pip freeze で書き出す)
置き場所 vendor/ node_modules/ 仮想環境(venv)
lock どおりに入れる composer install npm ci pip install -r requirements.txt
追加する composer require 名前 npm install 名前 pip install 名前
開発用だけ require --dev install --save-dev 別ファイルに分けるのが一般的
読み込み vendor/autoload.php を require require・import が node_modules を探す import が venv の中を探す

いちばん間違えやすいのは install の意味です。npm の npm install は lock を更新することがありますが、Composer の composer install は lock を書き換えません。npm で lock どおりに入れるのは npm ci で、Composer の install はこちらに近い動きです。npm のコマンドは関連記事「npm コマンド 一覧|package.json 書き方と実行結果・npm 12対応」、pip は関連記事「pipコマンド一覧|installのバージョン指定とrequirements.txt」で扱っています。

もう1つの違いは、Composer では読み込みの仕組み(autoload)までがパッケージ管理の一部になっていることです。PHP にはもともと「パッケージを探して読む」仕組みが無いため、Composer が作る autoload.php がその役を担っています。

よくある質問

Q. Composerとは何ですか? A. PHP のライブラリを、プロジェクトごとに入れて版をそろえる依存管理ツールです。composer.json に欲しいライブラリを書き、composer.lock に実際の版を残し、vendor/autoload.php でクラスを読み込めるようにします。

Q. composer install と composer update の違いは何ですか? A. install は composer.lock に書かれた版をそのまま入れ、lock を書き換えません。update は composer.json の範囲から版を決め直し、lock を書き換えます。この記事の実行例では、新しい版が出ていても install は前の版のまま、update で新しい版に上がりました。

Q. composer.lock は Git にコミットしますか? A. コミットします。全員が同じ版を使えるようにするためです。vendor はコミットせず、.gitignore に入れます。

Q. 本番サーバーで composer update を実行してよいですか? A. 避けます。テストしていない版が入る可能性があり、メモリも多く使います。本番は composer install --no-dev --optimize-autoloader にし、update は開発環境で実行して lock をコミットします。

Q. composer require と composer.json の手書きはどちらがよいですか? A. require です。版の範囲を自動で決め、失敗したら元に戻し、lock も同時に更新します。手で書いた場合は、続けて composer update 名前 を実行しないと lock と合わなくなります。

Q. ^ と ~ はどちらを使えばよいですか? A. 迷ったら ^ です。require が自動で付ける形で、互換が保たれる範囲(^1.2.3 なら 2.0.0 未満)を許します。~ は ~1.2 と ~1.2.3 で意味が変わるので注意します。

Q. Class not found と出ます。 A. autoload の設定を変えたあとに composer dump-autoload を実行したか、ファイル名とクラス名の大文字小文字、namespace とフォルダーの位置を確かめます。Windows・Mac では動いても Linux で落ちる原因は、大文字小文字のことが多いです。

Q. Do not run Composer as root と警告が出ます。 A. ライブラリのスクリプトが root の権限で動くことへの警告です。普段は一般ユーザーで実行します。Docker のように root で動かす前提の環境だけ、COMPOSER_ALLOW_SUPERUSER=1 で警告を止められます。

Q. composer の版を確かめる・更新するには? A. composer --version で確かめ、composer self-update で更新します。2026年10月29日時点の最新の安定版は、公式ダウンロードページで 2.11.0 です。

Q. composer global require は何に使いますか? A. プロジェクトに関係なく使うコマンドラインツールを COMPOSER_HOME に入れる仕組みです。使うには、グローバルの bin フォルダーを PATH に通します。プロジェクトで使うライブラリは global ではなく、プロジェクトの composer.json に入れます。

まとめ

  • Composer は PHP のライブラリをプロジェクトごとに入れ、版をそろえる道具。composer.json(希望)・composer.lock(結果)・vendor(置き場所)の3つで動き、json と lock を Git に入れる。
  • install は lock どおりに入れ、lock を書き換えない。update は版を決め直して lock を書き換える。実行例では、新しい版が出た日に install は 1.0.0 のまま、update で 1.1.0 に上がった(2.0.0 は依存の ^1.0 で止まった)。
  • 追加は composer require、本番は composer install --no-dev --optimize-autoloader。本番で update はしない。
  • autoload の設定を変えたら composer dump-autoload。-o で2,000クラスの読み込みが 6.05ms から 1.07ms になったが、効果は OPcache の効く Web サーバーで出る。
  • エラーは原文の Problem を下から読み、why-not で原因の依存を探す。PHP の版・拡張・メモリ・lock のずれ・minimum-stability がよくある原因。

次に読むとよい記事です。名前空間とフォルダーの対応は関連記事「PHP namespaceとuseの使い方|名前空間とPSR-4を図解」で、ファイルの読み込みの基本は関連記事「PHP include・requireの違い|require_onceと相対パス」で扱っています。

参考・出典

確認日はいずれも 2026年10月29日です。

  • Composer「Introduction」:https://getcomposer.org/doc/00-intro.md
  • Composer「Basic usage」:https://getcomposer.org/doc/01-basic-usage.md
  • Composer「Command-line interface / Commands」:https://getcomposer.org/doc/03-cli.md
  • Composer「The composer.json schema」:https://getcomposer.org/doc/04-schema.md
  • Composer「Repositories」:https://getcomposer.org/doc/05-repositories.md
  • Composer「Config」(secure-http・platform):https://getcomposer.org/doc/06-config.md
  • Composer「Troubleshooting」(Memory limit errors):https://getcomposer.org/doc/articles/troubleshooting.md
  • Composer「Resolving merge conflicts」:https://getcomposer.org/doc/articles/resolving-merge-conflicts.md
  • Composer「Download Composer」:https://getcomposer.org/download/
  • PHP-FIG「PSR-4: Autoloader」:https://www.php-fig.org/psr/psr-4/
  • Packagist:https://packagist.org/

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Composerとは?使い方とinstall・updateの違いを実行して解説」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ
参加受付中

AI駆動開発、 無料セミナー