[PHP]version_compareとは?バージョン番号を正しく比較する方法を徹底解説

PHP

はじめに

ソフトウェア開発において「バージョン1.10」と「バージョン1.9」のどちらが新しいかを比較したい場面は数多くあります。単純な文字列比較("1.10" < "1.9")や数値変換では、"1.10""1.9" より小さいと誤判定されてしまうなど、直感に反する結果になりがちです。

こうした問題を正しく解決してくれるのが version_compare() 関数です。この関数はPHP自身のバージョン管理規則に基づいて、"1.0.0-alpha""2.1.3-beta.2" のような複雑なバージョン文字列同士を正確に比較してくれます。ライブラリの互換性チェック、プラグインシステムでの要求バージョンの検証、アップデート通知機能の実装など、実務での応用範囲が広い関数です。本記事では基本的な使い方から実践的な活用例まで詳しく解説します。


関数概要

項目内容
関数名version_compare()
所属拡張コア関数(標準で常に利用可能)
シグネチャversion_compare(string $version1, string $version2, ?string $operator = null): int|bool
引数1$version1 — 比較対象のバージョン文字列1
引数2$version2 — 比較対象のバージョン文字列2
引数3$operator — 比較演算子("<", ">=" など)を指定すると真偽値を返す
戻り値$operator省略時は -1/0/1 の整数、指定時は bool
対応バージョンPHP 4.1.0以降
特殊対応dev, alpha, beta, RC, #, pl などのプレリリース識別子を正しく解釈する

比較の流れ(イメージ図)

  比較対象
  "1.10.0"  vs  "1.9.5"
        │
        ▼
  version_compare()
        │
   ┌────┴─────────────────────┐
   │ ドットで区切って各セグメントを │
   │ 数値として個別に比較する        │
   │ (単純な文字列比較はしない)      │
   └────┬─────────────────────┘
        ▼
  1番目: 1 == 1
  2番目: 10 > 9   ← ここで確定
        ▼
  結果: "1.10.0" は "1.9.5" より大きい (戻り値 1)

ポイントは、version_compare()バージョン文字列をドットやハイフンでセグメントに分割し、各セグメントを意味的に(数値または特別なキーワードとして)比較するという点です。これにより、単純な文字列比較や (float) へのキャストでは正しく扱えない "1.10" vs "1.9" のようなケースも正確に判定できます。


実践サンプル7選

例1:基本的な使い方

<?php

class BasicVersionComparator
{
    public function compare(string $v1, string $v2): int
    {
        // -1: v1 < v2、 0: 等しい、 1: v1 > v2
        return version_compare($v1, $v2);
    }
}

$comparator = new BasicVersionComparator();
echo $comparator->compare('1.10.0', '1.9.5') . PHP_EOL;  // 1 (1.10.0の方が新しい)
echo $comparator->compare('2.0.0', '2.0.0') . PHP_EOL;    // 0 (同じ)
echo $comparator->compare('1.0.0', '1.0.1') . PHP_EOL;    // -1 (1.0.0の方が古い)

例2:演算子を指定して真偽値で判定するクラス

<?php

class VersionRequirementChecker
{
    /**
     * 第3引数に演算子を指定すると、boolで結果を受け取れる
     */
    public function isAtLeast(string $currentVersion, string $requiredVersion): bool
    {
        return version_compare($currentVersion, $requiredVersion, '>=');
    }

    public function isOlderThan(string $currentVersion, string $targetVersion): bool
    {
        return version_compare($currentVersion, $targetVersion, '<');
    }
}

$checker = new VersionRequirementChecker();
var_dump($checker->isAtLeast('8.2.0', '8.0.0'));  // true
var_dump($checker->isOlderThan('7.4.0', '8.0.0')); // true

例3:PHPバージョンを確認して機能を分岐させるクラス

<?php

class PhpFeatureGate
{
    /**
     * 実行環境のPHPバージョンを確認し、
     * 利用可能な機能を動的に切り替える
     */
    public function supportsEnums(): bool
    {
        // PHP 8.1以降でネイティブのenumが利用可能
        return version_compare(PHP_VERSION, '8.1.0', '>=');
    }

    public function supportsReadonlyProperties(): bool
    {
        return version_compare(PHP_VERSION, '8.1.0', '>=');
    }
}

$gate = new PhpFeatureGate();
var_dump($gate->supportsEnums());
echo '現在のPHPバージョン: ' . PHP_VERSION . PHP_EOL;

例4:プレリリース版(alpha/beta/RC)を含むバージョンの比較

<?php

class PreReleaseVersionComparator
{
    /**
     * version_compare()はalpha < beta < RC < 正式版
     * という優先順位を正しく理解している
     */
    public function demonstrate(): array
    {
        return [
            '1.0.0-alpha vs 1.0.0-beta' => version_compare('1.0.0-alpha', '1.0.0-beta'),
            '1.0.0-beta vs 1.0.0-RC1'   => version_compare('1.0.0-beta', '1.0.0-RC1'),
            '1.0.0-RC1 vs 1.0.0'        => version_compare('1.0.0-RC1', '1.0.0'),
        ];
    }
}

$comparator = new PreReleaseVersionComparator();
print_r($comparator->demonstrate());
// すべて -1 (左辺の方が古い/低いバージョンとして扱われる)

例5:Composerパッケージの依存関係チェッカー

<?php

class DependencyVersionValidator
{
    /**
     * 複数の依存パッケージについて、
     * 要求される最小バージョンを満たしているか検証する
     */
    public function validate(array $installedVersions, array $requiredVersions): array
    {
        $issues = [];

        foreach ($requiredVersions as $package => $requiredVersion) {
            $installed = $installedVersions[$package] ?? null;

            if ($installed === null) {
                $issues[] = "{$package} がインストールされていません";
                continue;
            }

            if (version_compare($installed, $requiredVersion, '<')) {
                $issues[] = "{$package} のバージョンが古すぎます(インストール済み: {$installed}, 必要: {$requiredVersion}以上)";
            }
        }

        return $issues;
    }
}

$validator = new DependencyVersionValidator();
$issues = $validator->validate(
    ['guzzlehttp/guzzle' => '6.5.0', 'monolog/monolog' => '2.9.0'],
    ['guzzlehttp/guzzle' => '7.0.0', 'monolog/monolog' => '2.0.0']
);
print_r($issues);

例6:アプリの更新通知機能を実装するクラス

<?php

class AppUpdateNotifier
{
    /**
     * サーバーから取得した最新バージョンと、
     * インストール済みのバージョンを比較して更新通知の要否を判定する
     */
    public function shouldNotifyUpdate(string $installedVersion, string $latestVersion): bool
    {
        return version_compare($latestVersion, $installedVersion, '>');
    }

    public function isCriticalUpdate(string $installedVersion, string $latestVersion): bool
    {
        // メジャーバージョンが変わっている場合は重要な更新とみなす例
        $installedMajor = (int) explode('.', $installedVersion)[0];
        $latestMajor = (int) explode('.', $latestVersion)[0];

        return $latestMajor > $installedMajor
            && version_compare($latestVersion, $installedVersion, '>');
    }
}

$notifier = new AppUpdateNotifier();
var_dump($notifier->shouldNotifyUpdate('1.4.2', '1.5.0'));    // true
var_dump($notifier->isCriticalUpdate('1.4.2', '2.0.0'));       // true

例7:バージョンリストをソートするクラス

<?php

class VersionListSorter
{
    /**
     * usort()とversion_compare()を組み合わせて
     * バージョン文字列の配列を正しい順序でソートする
     */
    public function sortAscending(array $versions): array
    {
        usort($versions, fn (string $a, string $b) => version_compare($a, $b));
        return $versions;
    }

    public function sortDescending(array $versions): array
    {
        usort($versions, fn (string $a, string $b) => version_compare($b, $a));
        return $versions;
    }
}

$sorter = new VersionListSorter();
$versions = ['1.10.0', '1.2.0', '1.9.5', '2.0.0-beta', '2.0.0'];
print_r($sorter->sortAscending($versions));
// ['1.2.0', '1.9.5', '1.10.0', '2.0.0-beta', '2.0.0']

関連関数との比較

関数役割version_compareとの違い
version_compare()バージョン文字列同士を意味的に比較本記事の対象。プレリリース識別子まで正しく解釈する
phpversion()現在のPHPまたは拡張のバージョンを取得比較用の文字列を取得する側の関数であり、比較自体は行わない
PHP_VERSION / PHP_VERSION_ID定数として現在のPHPバージョンを保持PHP_VERSION_IDは整数比較用、version_compare()は文字列ベースでより柔軟
strcmp()単純な文字列比較バージョン番号の意味を理解せず、辞書順で比較してしまうため誤判定しやすい
strnatcmp()自然順(数値を意識した)文字列比較ある程度は数値を考慮するが、alpha/beta等のプレリリース識別子は理解しない

よくある落とし穴(注意点)

  1. 単純な文字列比較や(float)キャストで代用しようとする "1.10"(float) にキャストすると 1.1 になってしまい、"1.9"1.9 より小さいと誤判定されます。バージョン比較には必ず version_compare() を使いましょう。
  2. PHP_VERSION_ID との使い分けを誤る PHP自身のバージョンをチェックする場合、PHP_VERSION_ID >= 80100 のような整数比較の方が高速でシンプルな場合もあります。version_compare() は任意の文字列(自作アプリのバージョンや外部パッケージのバージョンなど)を比較したい場合に特に有用です。
  3. プレリリース識別子の大文字小文字の扱い "RC""rc" は内部的に同じ優先順位として扱われますが、独自のバージョン管理規則を持つプロジェクトでは、想定通りの挙動になっているか事前にテストしておくと安心です。
  4. セマンティックバージョニング以外の独自形式には対応しきれない場合がある version_compare() はPHP独自のバージョン比較規則に基づいており、一般的な major.minor.patch 形式には強く対応していますが、日付ベースのバージョン(例: "2026.08.17")や完全に独自の形式では期待通りに動かない可能性があります。
  5. 演算子文字列のタイプミスに注意する 第3引数の演算子は "<", "lt", "<=", "le", ">", "gt", ">=", "ge", "==", "=", "eq", "!=", "<>", "ne" などの決まった文字列である必要があります。誤った文字列を指定すると null が返るため、事前にドキュメントで正確な表記を確認しましょう。

まとめ

観点まとめ
何をする関数か2つのバージョン文字列を意味的に正しく比較する
主な用途PHP/ライブラリのバージョンチェック、依存関係の検証、更新通知機能、バージョンリストのソート
特徴alpha/beta/RCなどのプレリリース識別子まで正しく解釈する
類似機能との違い単純な文字列比較やstrnatcmp()よりも、バージョン番号の意味論に忠実
注意点(float)キャストでの代用は不可、PHP_VERSION_IDとの使い分け、演算子文字列の正確な指定

version_compare() は、一見地味ながらソフトウェアの互換性管理において非常に重要な役割を果たす関数です。単純な数値比較では対応しきれないバージョン番号の複雑さを正しく扱えるこの関数を活用し、堅牢な互換性チェックやアップデート機能を実装していきましょう。

タイトルとURLをコピーしました