バックエンド 2026.08.11

PHP 8系移行で「動いていたコード」が壊れる本当の理由と事前テスト手順

約13分で読めます

PHP 7系から8系への移行で突然サイトが壊れるのはなぜ?後方互換性の破壊的変更と、安全に移行するための実践的テスト手順を解説します。

「昨日まで動いていたのに、なぜ?」

こんな経験はありませんか?

サーバー会社から「PHP 7.4のサポートが終了します。PHP 8.x への移行をお願いします」というメールが届き、「まあ大丈夫だろう」と気軽にバージョンを切り替えたら、翌朝サイトが真っ白になっていた——。

Fivenine Design にも、そういったご相談が年に数件届きます。先日も、神奈川県内の製造業のクライアントから「WordPressサイトが急に表示されなくなった。PHP を 8.1 に上げた直後から」とお問い合わせをいただきました。原因を調べると、長年使ってきたプラグインが PHP 8 で廃止された関数に依存していたことが判明。バックアップからの切り戻しと修正対応に丸1日かかりました。

PHPのバージョンアップは「アップデート」ではなく「移行」です。 同じ言語であっても、8系は7系と比べて数十箇所にわたる「後方互換性を壊す変更(Breaking Changes)」が含まれています。この記事では、なぜコードが壊れるのかという根本的な理由と、本番環境に手を触れる前に実施すべき事前テストの手順を、実際の現場経験をもとに解説します。


なぜ「動いていたコード」が壊れるのか

PHP のメジャーバージョンアップには、後方互換性のない変更(Breaking Changes) が必ず含まれています。これは「古い書き方を許容しなくなった」という意味であり、構文エラーや型の扱いの厳格化が主な原因です。

PHP 8系の主要な破壊的変更

① 廃止された関数・クラス

PHP 8.0 で each() 関数が削除され、create_function() も使えなくなりました。PHP 8.1 では mysqli_connect() のデフォルト引数の扱いが変わり、古いWordPressプラグインで頻繁にエラーが発生します。

② 型の厳格化(Type Coercion の変更)

PHP 7 までは文字列 "1" を数値 1 として暗黙的に扱っていましたが、PHP 8 では内部的な型変換ルールが変更されました。特に、match 式の導入と厳格な比較(===)の推奨が、既存の switch 文依存のロジックを壊すことがあります。

③ エラーから例外への昇格

7系では「警告(Warning)」として素通りしていたものが、8系では TypeErrorValueError として例外を投げるようになりました。try-catch で囲んでいないコードは、そこで処理が止まります。

// PHP 7: 警告を出しながらも動作した
$result = 0 + "10 apples";
echo $result; // 10

// PHP 8.1+: Deprecation Notice が出るようになった
// 将来的には TypeError に昇格予定
$result = 0 + "10 apples";
// Deprecated: Implicit conversion from float-string "10 apples" to int

null の扱いの厳格化

PHP 8.1 から導入された never 型や、Fibers、Enum など新機能の追加と並行して、null を文字列関数に渡すことが非推奨になりました。

// PHP 8.1 で Deprecated Warning が出るコード
$str = null;
echo strlen($str); // Deprecated: Passing null to non-nullable

// 正しい書き方
echo strlen($str ?? '');

こういった変更が数十個積み重なると、大規模なプロジェクトほど影響箇所が多く、単純なバージョン切り替えでは必ず問題が発生します。


バックエンド開発でお困りですか?

API設計・DB最適化・システム構築など、ご相談ください

無料で相談する

事前テストの実践手順

「本番で試して壊れたら戻せばいい」という発想は非常に危険です。切り戻しの間もサイトはダウンし続け、SEOへの悪影響やユーザーの離脱につながります。以下の手順で 本番を触る前に問題を洗い出す ことが鉄則です。

Step 1: 静的解析ツールで問題箇所を一覧化する

まず手を動かすより前に、PHP_CodeSnifferRector を使った静的解析を実施します。コードを実行せずに「PHP 8 で問題になる書き方」を検出できます。

# PHP_CodeSniffer のインストール
composer require --dev squizlabs/php_codesniffer

# PHP 8 互換性チェックプラグインの追加
composer require --dev phpcompatibility/php-compatibility

# プロジェクト全体をスキャン(PHP 8.1 を対象に)
./vendor/bin/phpcs --standard=PHPCompatibility \
  --runtime-set testVersion 8.1 \
  --extensions=php ./src

Rector の設定ファイルは以下のように記述します。

// rector.php
use Rector\Config\RectorConfig;
use Rector\Set\ValueObject\LevelSetList;

return static function (RectorConfig $rectorConfig): void {
    $rectorConfig->paths([
        __DIR__ . '/src',
        __DIR__ . '/app',
    ]);

    // PHP 8.0 → 8.1 への移行ルールを適用
    $rectorConfig->sets([
        LevelSetList::UP_TO_PHP_81,
    ]);
};

Step 2: ローカル環境またはステージング環境でPHPバージョンを切り替える

Dockerを使っている場合は docker-compose.yml の PHP イメージを変更するだけで切り替え可能です。本番と同じデータを使ったステージング環境があるなら、そちらで先に試します。

# docker-compose.yml
services:
  app:
    image: php:8.1-fpm  # 7.4 から変更
    volumes:
      - ./src:/var/www/html

Step 3: エラーログを有効にしてすべての Warning を可視化する

本番では通常エラーを非表示にしていますが、テスト環境では すべての警告を表示 させます。PHP 8 への移行では、Fatal Error だけでなく DeprecatedWarning も将来の破壊的変更の予兆です。

// php.ini または .htaccess で設定
error_reporting(E_ALL);
ini_set('display_errors', '1');
ini_set('log_errors', '1');
ini_set('error_log', '/var/log/php_errors.log');

Step 4: 自動テストで動作確認(PHPUnit)

テストコードがある場合は、PHP バージョンを変更した状態でテストスイートをすべて実行します。テストが存在しない場合でも、最低限クリティカルな処理(決済、フォーム送信、ログインなど)は手動で確認します。

# PHPUnit でテスト実行
./vendor/bin/phpunit --stop-on-failure

# Laravel プロジェクトの場合
php artisan test --parallel
flowchart TD
    A[PHP 8移行開始] --> B[静的解析\nPHP_CodeSniffer / Rector]
    B --> C{問題箇所あり?}
    C -->|Yes| D[コード修正・\nRectorで自動修正]
    D --> B
    C -->|No| E[ステージング環境で\nPHPバージョン切替]
    E --> F[エラーログ全開で\n動作確認]
    F --> G{エラー・警告あり?}
    G -->|Yes| H[修正対応]
    H --> F
    G -->|No| I[自動テスト実行]
    I --> J{テスト通過?}
    J -->|Yes| K[本番移行]
    J -->|No| H

よくある失敗パターンと対処法

失敗1: プラグイン・ライブラリの確認を怠る

自社コードは問題なくても、使用しているライブラリやWordPressプラグインが PHP 8 未対応 というケースが非常に多いです。冒頭のクライアント事例もこれでした。

対処法として、composer outdated コマンドで依存ライブラリの最新状況を確認し、各パッケージの GitHub リリースノートで「PHP 8.x」への対応を明示しているかをチェックします。WordPressの場合、プラグインのページに「テスト済みの最新バージョン」が表示されているので必ず確認してください。

失敗2: ===== の混在

PHP 8 では比較演算子の型処理が変わりました。0 == "foo" が PHP 7 では true を返していましたが、PHP 8 では false になります。認証ロジックや条件分岐に == を多用しているコードは要注意です。

// PHP 7: true(危険な挙動)
var_dump(0 == "foo"); // bool(true)

// PHP 8: false(正しい挙動)
var_dump(0 == "foo"); // bool(false)

// 型を明示した比較に書き換えることが推奨
var_dump(0 === "foo"); // bool(false) ← こちらに統一する

失敗3: 移行後にバックアップを取っていない

「バックアップは移行前に取ればいい」と思われがちですが、移行作業中にも定期的にスナップショットを残す ことが重要です。修正が複数回にわたる場合、どの時点まで戻すかが問題になります。本番移行の直前に最新バックアップを取得し、切り戻し手順を事前に文書化しておきましょう。


バックエンド開発でお困りですか?

API設計・DB最適化・システム構築など、ご相談ください

無料で相談する

開発・運用でお困りなら

システム開発

設計から運用まで、堅牢なシステムを構築します

200件以上の制作実績 顧客満足度97% 初回相談無料

※ 通常1営業日以内にご返信します

まとめと次のステップ

PHP 8 への移行を安全に進めるには「とりあえず上げてみる」ではなく、静的解析 → ステージングでの検証 → 自動テスト という段階を踏むことが欠かせません。特に長く運用してきたサイトほど、誰も把握していない古いコードが潜んでいるものです。

Fivenine Design では、PHP バージョン移行の事前診断から修正対応・本番切替まで一貫してサポートしています。「自分でやってみたが、どうしても解消できないエラーがある」「移行してみたいが怖くて踏み出せない」という方は、お気軽にご相談ください。20年以上の実績で、安全な移行をお手伝いします。

この記事をシェア

システム開発のご相談、受付中です

設計・開発・テスト・運用まで、ビジネスに合ったシステムを構築します。 初回相談は無料です。

※ 1営業日以内にご返信いたします

この技術でお困りなら

無料でプロに相談できます

相談する
AIに無料相談