この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:5
ページ更新者:爽健
更新日時:2026-06-11 07:12:00

タイトル: クラスの再読み込み
SEOタイトル: PHP / Java のクラス再読み込み完全ガイド(OPcache, autoload, ClassLoader, ホットデプロイ)

この記事の要点
  • PHP はリクエストごとに全クラスを再読み込みするが、本番は OPcache がバイトコードをキャッシュするためソース変更が即反映されない
  • OPcache の手動クリアは opcache_reset() / 個別ファイルは opcache_invalidate("/path/file.php")
  • Laravel では php artisan optimize:clear でルート/設定/ビュー/イベントの全キャッシュを一括クリア
  • Composer で新クラスを認識させるには composer dump-autoload -o(autoload マップ再生成)
  • Java は ClassLoader 単位で再読み込み: URLClassLoader を破棄して新規生成、または Spring DevTools / JRebel でホットデプロイ

「クラスの再読み込み」とは

サーバ側プログラムにおいて、編集したソースコードを再起動なしで反映させる仕組みを指します。言語・フレームワークごとに事情が異なります:

言語/環境デフォルト挙動キャッシュ層再読み込み手段
PHP(OPcache 無)毎リクエスト再読み込みなし不要
PHP(OPcache 有・本番)初回のみコンパイルバイトコードキャッシュopcache_reset()
Laravelconfig / route / view をキャッシュbootstrap/cacheartisan optimize:clear
Java (Tomcat 等)起動時に ClassLoader でロードJVM Method AreaClassLoader 再生成 / 再デプロイ
Node.jsrequire はキャッシュrequire.cachenodemon / delete require.cache[...]

PHP: OPcache のクリア

PHP 7+ では OPcache がデフォルト ON。本番でファイルを更新しても、OPcache の検証間隔(opcache.revalidate_freq)が経過するまで古いコードが動き続けることがあります。

<?php
// 全クラス / 全ファイルのバイトコードキャッシュを破棄
opcache_reset();

// 個別ファイルだけ無効化
opcache_invalidate(__DIR__ . '/MyClass.php', true);

// 状態確認
$status = opcache_get_status();
print_r($status['memory_usage']);
print_r($status['opcache_statistics']);

// 設定確認
echo ini_get('opcache.enable') . PHP_EOL;            // 1
echo ini_get('opcache.validate_timestamps') . PHP_EOL; // 1
echo ini_get('opcache.revalidate_freq') . PHP_EOL;   // 2 (秒)

本番サーバで反映するなら、Web からアクセスできる opcache-clear.php を一時的に置くか、CLI で cachetool を使います:

# cachetool で FPM の OPcache をクリア
cachetool opcache:reset --fcgi=127.0.0.1:9000

# php-fpm を reload する(USR2 シグナル)
sudo systemctl reload php8.2-fpm
# または
sudo killall -USR2 php-fpm

Laravel のキャッシュクリア

Laravel は OPcache に加え、設定/ルート/ビュー/イベントのキャッシュを独自に持ちます。クラスを追加・変更したら次のいずれかを実行:

# 全部まとめてクリア(推奨)
php artisan optimize:clear

# 個別
php artisan cache:clear      # アプリケーションキャッシュ
php artisan config:clear     # config キャッシュ
php artisan route:clear      # route キャッシュ
php artisan view:clear       # Blade コンパイル済キャッシュ
php artisan event:clear      # イベント/リスナーキャッシュ

# 新しいクラスを追加した時
composer dump-autoload -o

# 本番再構築(キャッシュを作り直す)
php artisan config:cache
php artisan route:cache
php artisan view:cache

Composer Autoload マップ再生成

新しいクラスを追加したが Class not found が出る場合、autoload マップに登録されていません:

# autoload.php と classmap を再生成
composer dump-autoload

# 本番向け最適化(classmap-authoritative)
composer dump-autoload -o --classmap-authoritative

# composer.json の autoload セクション例
# &quot;autoload&quot;: {
#     &quot;psr-4&quot;: { &quot;App\\&quot;: &quot;app/&quot; },
#     &quot;classmap&quot;: [&quot;database/seeders&quot;, &quot;database/factories&quot;]
# }

Java: ClassLoader 単位の再読み込み

JVM は同じ ClassLoader で同名クラスを二重にロードできない仕様。再読み込みするには新しい ClassLoader を作るか、既存をまるごと破棄します:

import java.net.URL;
import java.net.URLClassLoader;
import java.lang.reflect.Method;

public class ReloadDemo {
    public static void main(String[] args) throws Exception {
        URL[] urls = { new java.io.File("plugins/").toURI().toURL() };

        // 1 回目のロード
        URLClassLoader loader1 = new URLClassLoader(urls);
        Class<?> c1 = loader1.loadClass("com.example.Plugin");
        Method m1 = c1.getDeclaredMethod("run");
        m1.invoke(c1.getDeclaredConstructor().newInstance());
        loader1.close();  // 必須

        // JAR を入れ替えてから 2 回目のロード(新しい ClassLoader で)
        URLClassLoader loader2 = new URLClassLoader(urls);
        Class<?> c2 = loader2.loadClass("com.example.Plugin");
        Method m2 = c2.getDeclaredMethod("run");
        m2.invoke(c2.getDeclaredConstructor().newInstance());
        loader2.close();
    }
}

Java: ホットデプロイの実用解

  • Spring Boot DevTools: spring-boot-devtools 依存追加で、classpath 変更を自動検知 → アプリ再起動(高速)
  • JRebel: 商用ツール。クラス/メソッド追加もホット反映
  • Tomcat Manager: WAR 再デプロイ用 API(/manager/text/reload
  • Jakarta EE 互換サーバ: WildFly / Payara は配布ディレクトリの WAR 入れ替えで自動再ロード

確認: 本当に新しいコードが動いているか

<?php
// クラスがどのファイルから読み込まれたか
$ref = new ReflectionClass('App\\Services\\MyService');
echo $ref->getFileName() . PHP_EOL;
echo $ref->getStartLine() . PHP_EOL;

// OPcache が見ているタイムスタンプを確認
$status = opcache_get_status(true);
foreach ($status['scripts'] as $file => $info) {
    if (str_contains($file, 'MyService.php')) {
        echo "timestamp=" . date('Y-m-d H:i:s', $info['timestamp']) . PHP_EOL;
    }
}

FAQ

Q: optimize:clear しても反映されない
A: PHP-FPM の OPcache は別プロセスで保持されています。sudo systemctl reload php-fpm も併用してください。

Q: 本番で OPcache を切ってよいか
A: 切ると性能が 3〜10 倍劣化します。opcache.validate_timestamps=1 + revalidate_freq=2 で運用が現実解。

Q: Java で java.lang.LinkageError: loader constraint violation
A: 2 つの ClassLoader が同名クラスを別々にロードしました。Class インスタンスを ClassLoader 境界をまたいでキャストするとこのエラーになります。