RAKUS Developers Blog | ラクス エンジニアブログ

株式会社ラクスのITエンジニアによる技術ブログです。

PHPerのための「Composer」を語り合う【PHP TechCafe イベントレポート】

特集:「Composer」を語り合う

弊社で毎月開催し、PHPエンジニアの間で好評いただいているPHP TechCafe。
2022年6月のイベントでは「Composer」について語り合いました。

弊社のメンバーが事前にまとめてきたComposerの基礎知識や使い方の情報にしたがって、他の参加者に意見を頂いて語り合いながら学びました。
今回はその内容についてレポートします。

rakus.connpass.com

Composer とは

概要

プロジェクトの依存関係管理ツール

Composer の主な機能はプロジェクトの依存関係管理機能です。
プロジェクトで使用するパッケージの依存関係をまとめて管理することができます。

専用の設定ファイル (composer.json) に必要なパッケージを定義してコマンドを実行するだけで、
プロジェクト内の vendor ディレクトリにパッケージがインストールされます。

つまり設定ファイルさえあれば、プロジェクト新規参入者でもコマンド1つで簡単に環境構築を行うことが可能です。

オートローディング

オートローディングとは読み込みたいファイルを include / requrire することなく、
自動でファイルを読み込んでくれる機能です。

Composer では PSR-4 に基づいた名前空間を宣言します。
プロジェクト内の指定したディレクトリ配下を名前空間として使用可能にします。

公式ページ

Composer の公式ドキュメントやダウンロードは↓コチラです。
getcomposer.org

公式ページにアクセスすると指揮者のようなアイコンが表示されます。

Composer のアイコンはリロードするたびに色が変わります。
是非公式サイトにアクセスして試してみてください。

※※※ 稀にあまり目に優しくないチェック模様になります ※※※

アクセスするたびに色が変わることに気づいていたが、
バージョンによるものだと思っている方もいらっしゃいました。

使い方

基本的な使い方は公式ドキュメントに沿って、 monolog を例に説明されました。

1. composer.json を作成

Composer を導入したいプロジェクトに composer.json という名前のファイルを作成します。
require をキーとし、使用したいパッケージを vendor名/プロジェクト: バージョン の形式で指定します。

使用したいパッケージの vendor 名やプロジェクト、バージョンについては Packegest というサイトで確認することができます。

monolog を指定する場合

{
  "require": {
      "monolog/monolog": "3.1.*"
  }
}

バージョンの指定には下記ルールが適用されます。

  • vX.Y.Z または X.Y.Z で指定する
  • ワイルドカードが指定されている箇所は最新を取得するようにする
    • 上記例では 3.1 系の最新が取得される
    • 3.1.*>=3.1, < 3.2 と同じ意味

2. 依存関係のインストール

下記コマンドを実行することで composer.json に定義されたパッケージがインストールされます。

php composer.phar update

このコマンドは大きく分けて2つの処理を行っています。

  1. composer.lock の作成 / 更新
    • composer.json を基にインストールするパッケージのバージョンを確定させる
  2. 暗黙的に composer.phar install を実行
    • vendor ディレクトリを作成して必要なパッケージを取得

composer.lock の Git 管理について

composer.lockcomposer.phar update コマンドで自動生成されるファイルです。

自動生成されるファイルを Git 管理するか否かはよく議論になるとおもいます。
composer.lock を Git 管理するとよいケース/管理しないほうがよいケースについて、 それぞれ紹介されていました。

Git 管理するとよいケース

composer.lock を Git 管理するとよいケースとして、パッケージのバージョンを固定したい場合が挙げられていました。

アプリケーション開発などでパッケージのバージョンを固定したい場面がよくあると思います。

composer.lock はバージョンが明記されており、どの環境にも同一バージョンのパッケージをインストールすることが可能なため、 composer.lock を Git 管理し、チーム内で共有することがおすすめされていました。

Git 管理しないほうがよいケース

composer.lock の Git 管理をしないほうがよいケースとして、composer.lock の内容が都度変更される場合 が挙げられていました。

PHP の複数バージョン (5.4~8等) に対応したパッケージの開発ではバージョンごとで composer.lock の内容が変わってしまいます。
そのため composer.lock はあえて .gitignore に入れ、都度 composer.phar update することがおすすめされていました。

composer.lock のコンフリクト対策

composer.lock を Git 管理するという話から、

  • 複数の開発する場合、composer.lockでコンフリクトが起きるケースがよくあります。
    対応策などあったりしますか?

という質問がありました。

この質問に対して参加者から様々な解決方法が寄せられました。

  • composer.json/composer.lock を弄るときはさっさとメインブランチに入れる、が解だと思います
  • コンフリクトした人が master (main) から composer require / composer update しなおす
  • ブランチごとに無関係のパッケージだったら composer.lock のコンフリクトだけなので気合で解消できる
  • git rebase -i が可能なら、git checkout HEAD composer.lock で戻してから composer require しなおします

また、「コンフリクトに対しては密なコミュニケーションが重要」や「神速でマージすれば問題ないのでは」といった意見も挙がりました。

Packegest

前述の通り、 Packegest は Composer で使用したいパッケージの情報を確認するサイトです。

Packegest では登録されているパッケージを利用するだけでなく、
自身で作成したパッケージを Packagest に登録することも可能です。

自作パッケージの登録方法

下記の4ステップで Packagest にパッケージを登録することができ、
非常に手軽だと参加者から驚きの声があがっていました。

1. composer.json 作成

Copmoser 利用時と同様に、まず composer.json を作成します。
作成後、下記例のようにパッケージの詳細を記載します。

monolog の composer.json

{
  "name": "monolog/monolog",
  "type": "library",
  "description": "Logging for PHP 8.0",
  "keywords": ["log","logging"],
  "homepage": "https://github.com/Seldaek/monolog",
  "license": "MIT",
  "authors": [
    {
      "name": "Jordi Boggiano",
      "email": "j.boggiano@seld.be",
      "homepage": "http://seld.be",
      "role": "Developer"
    }
  ],
  "require": {
    "php": ">=8.0.0"
  },
  "autoload": {
    "psr-0": {
      "Monolog": "src"
    }
  }
}

Packagest の monolog ページと見比べて、どの設定がどの項目に反映されるかを確認してください。

2. コマンド実行

2つのコマンドを実行します。

1.composer.lock 更新

php composer.phar update

2.composer.json の書式チェック

php composer.phar validate

3. GitHub 等に push

いつも通り、git push してください。

4. Packagist に登録

最後に Packagest にログイン後、GitHub と紐づけます

登録の手軽さと怖さ

GitHub に push して紐づけてしまえばすぐに登録されるという手軽さから、
誰の査読も受けていないパッケージを登録できてしまうのが怖いという意見がありました。

これをきっかけに

「Packagest はパッケージ名にユーザ名や組織名が付くため、"だれが作ったかわからない" というリスクは少ないですね」
「npm などでは短い名前のデファクトっぽいパッケージ、例えば 〇〇 parser を適当に選んで使いがちですもんね」
「確かに 〇〇 parser って簡潔な名前だとそれが王道なのかなって思っちゃいますもんね」
OSS 全体で言えることですが、より信頼できるパッケージを選びたいですね」

という話題で盛り上がりました。

private 版

Packagest の private 版も紹介されました。
有料にはなりますが、クラウド/自前のサーバどちらにもインストール可能です。

社内でオリジナルのパッケージを配布したいときに有効であるという意見がありました。

オートローディング

続いて Composer の主機能の1つであるオートローディングについて紹介されました。

オートローディングとは

まずはオートローディングとは?という基本的な説明が行われました。

オートローディングとは何度も include / requrire しなくても自動的にファイルを読み込んでくれる機能です。

昔ながらのPHPプロジェクトでは includerequrireズラーッと並ぶことが多いと思います。
シンプルなら問題ないですが、大半の場合はクラスごとに依存関係があるため読み込み順など管理が困難です。

<?php

/**
 * 各ファイルから共通で読み込まれる
 */

namespace TechCafe;

include_once __DIR__ . '/Hoge.php';
include_once __DIR__ . '/Fuga.php';
include_once __DIR__ . '/Piyo.php';
include_once __DIR__ . '/Hogera.php';
include_once __DIR__ . '/HogeHoge.php';
include_once __DIR__ . '/Foo.php';
include_once __DIR__ . '/Bar.php';
include_once __DIR__ . '/Baz.php';
include_once __DIR__ . '/Foobar.php';
// etc...etc...

そこで PHP には spl_autoload_register() というクラスローダを登録するメソッドが用意されています。

クラスローダとは引数に指定されたクラス名を読み込む機能を持った関数です。
spl_autoload_register() には独自実装したクラスローダの関数名または無名関数をセットできます。

<?php

/**
 * 各ファイルから共通で読み込まれる
 */

namespace TechCafe;

// 無名関数でクラスローダをセット
spl_autoload_register(function ($class) {
    include 'classes/' . $class . '.class.php';
});

難しく感じるかもしれませんが、include / requrire の定義する代わりにを自動で読み込んでいるだけです。

Composer を使ったオートローディング

Composer を使えば、自前でクラスローダを実装することなくオートローディングを利用できます。

使い方

composer.json に設定を追加し、コマンドを一度だけ実行します。
コマンド実行後は vendor/autoload.php を読み込むだけでオートローディングを利用できます。

composer.json

{
  "autoload": {
    "psr-4": {
      "TechCafe\\": "src/"
    }
  }
}

コマンド実行

php ./composer.phar dump-autoload

autoload.php 読み込み

<?php

/**
 * 各ファイルから共通で読み込まれる
 */

namespace TechCafe;

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

spl_autoload_register() の時のような独自実装もなく、
たったこれだけで include / requrire 地獄から解放されます。

クラス名とファイル名が必ずしも一致してない場合

上記設定でオートローディングを利用できますが、正常に読み込みが行われるのはクラス名とファイル名が一致している場合のみです。
既存プロジェクトでクラス名とファイル名が一致していない場合や、クラス名はキャメルケースだけどファイル名はスネークケースの場合等あると思います。

そんな場合は configmap を定義することで対応可能です。

例)src/tools/test_util.php を読み込みたい場合

<?php

namespace TechCafe

class TestUtil {
  public static function getTest() {
    return "てすとだよ";
  }
}

composer.jsonclassmap を設定し、コマンドを実行します。

composer.json

{
  "autoload": {
    "classmap": ["src/tools"],
    "psr-4": {
      "TechCafe\\": "src/"
    }
  }
}

コマンド実行

php ./composer.phar dump-autoload

classmap は有用ですが、デメリットもあります。
新しくクラスを追加した場合、psr4 で指定した場合はコマンドの再実行は不要ですが、
classmap で指定した場合は再度 dump-autoload を実行しなければクラスを読み込めません。

レガシープロジェクトなどでは難しいとは思いますが、
可能な限り、再実行の手間なく読み込むことができる psr-4 での指定が推奨されていました。

関数をオートローディングしたい場合

オートローディングに対応しているのは class や trait、interface のみです。
そのため global に定義された関数をオートローディングしたい場合は別途読み込む必要があります。

例)src/functions.php に定義された getHoge() を読み込みたい場合

<?php

namespace TechCafe

function getHoge() {
  return "Hoge!!";
}

composer.json に files を設定することで対応可能です。

{
  "autoload": {
    "classmap": ["src/tools"],
    "files": ["src/functions.php"],
    "psr-4": {
      "TechCafe\\": "src/"
    }
  }
}

Composer オートローディングのパフォーマンス

通常ファイルの読み込みを行う場合、コロン区切りで指定されたディレクトリ (include_path) を順に走査を行います。
そのため、指定されたディレクトリの分だけ走査が行われパフォーマンスが悪くなっていました。

Composer のオートローディングはファイルの走査処理が最適化されており、
通常の読み込み処理に比べパフォーマンスが良くなっています。

また、Composer のオートローディングは遅延ロードとなっているのもパフォーマンス上でメリットといえます。
※遅延ロード:ファイルが必要になった時に読み込み処理を行うこと

例えば下記のような if 文があった場合、 $i が numeric なら HOGE が、そうでないなら FUGA が読み込まれます。

<?php

if(is_numeric($i)) {
  HOGE::getHoge();
} else {
  FUGA::getFuga();
}

参加者からは「レガシープロジェクトでも設定次第で Composer のオートローディングの恩恵を受けられるので適用したい」といった声があがっていました。

Composer2.0.0

最後に Composer 8年ぶりのメジャーバージョンアップである Composer 2.0.0 についての紹介です。

概要

新機能や変更点

Performance improvements

Composer2 の大きな変更点としてパフォーマンスの改善が紹介されていました。
速度とメモリ使用量の両方が大幅に改善され、Composer1 と比べ 50% 以上の改善が見られたそうです。

この驚異的な改善に参加者から「これはすごい」「めちゃくちゃ速くなっている」という驚きの声があがっていました。
またパフォーマンス改善の要因として、パッケージ構造の変更による効率化が挙げられていました。

https://blog.packagist.com/content/images/2020/10/image_2020-10-24_175318.png

Architectural changes and determinism

require/update 実行時の vendor ディレクトリ更新処理が中途半端に行われることが無くなりました。

Composer1 では更新中に LAN ケーブルが抜ける等でネットワークが切れた場合、
vendor ディレクトリが更新途中の状態になり復旧不可能になっていました。

Composer2 ではネットワークを跨いだ処理 (パッケージのダウンロード等) を全て終わらせてから更新を行うよう変更されたため、 更新中にネットワークが切れたとしても vendor ディレクトリが壊れることが無くなりました。

参加者からは「この機能は必須」や「更新するときの安心感が段違い」といった意見が寄せられていました。

Runtime features

オートロード時にプラットフォームチェック機能が追加されました。

vendor/autoload.php が呼ばれた際、現在のPHPバージョンやエクステンションが対応したバージョンであるかをチェックし、一致していなければエラーにします。

Error reporting improvements

依存関係が解決できない場合に表示されるエラーの内容が改善されました。

Composer1 のエラー情報はごちゃごちゃしていたので、Composer2 で色がついたり見やすくなって嬉しいという意見がありました。

Partial updates with temporary constraints

特定のパッケージのバージョンを更新するためのコマンドが追加されました。

composer update vendor/package:1.0.*

↓では composer.jsoncmposer.lock を更新したい場合は --with を付ける

composer update --with vendor/package:1.0.*

ちなみに Composer1 でも required パッケージ名 を実行することで特定のパッケージを更新することができると紹介されていました。

編集後記

以上、Composer の概要と Composer2.0.0 の変更点について取り上げました。
Composer はパッケージの依存関係管理だけでなくオートローディングまで備えているため、
Composer を利用しない開発はありえないなと感じました。

Composer は現在でも4~5ヵ月ごとにマイナーバージョンアップされており、
積極的に開発が行われています。

今後も Composer の新機能や改善などに着目していきたいと思います!

PHP TechCafe」では今後もPHPに関する様々なテーマのイベントを企画していきます。
皆さまのご参加をお待ちしております。

connpass.com


エンジニア中途採用サイト
ラクスでは、エンジニア・デザイナーの中途採用を積極的に行っております!
ご興味ありましたら是非ご確認をお願いします。
20210916153018
https://career-recruit.rakus.co.jp/career_engineer/

カジュアル面談お申込みフォーム
どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。
以下フォームよりお申込みください。
rakus.hubspotpagebuilder.com

ラクスDevelopers登録フォーム
20220701175429
https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/

イベント情報
会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください!

◆TECH PLAY
techplay.jp

◆connpass
rakus.connpass.com

Copyright © RAKUS Co., Ltd. All rights reserved.