エラーが突然発生する
アプリは正常に動いていました。最新のコードをプルして素早くデプロイしたら、すべてのページでこのエラーが発生するようになりました:
Fatal error: Uncaught Error: Class 'App\Services\PaymentService' not found in /var/www/html/src/Controllers/CheckoutController.php:42
Stack trace:
#0 {main}
thrown in /var/www/html/src/Controllers/CheckoutController.php on line 42
あるいはStripe\ChargeやCarbon\Carbonといったサードパーティのクラスかもしれません。いずれにしても、PHPはクラスを見つけられず、実行が完全に止まってしまいます。
6つの根本原因がこうした失敗の99%をカバーしています。この順番で一つずつ確認してください — 各ステップで次に疑わしい原因を排除できます。
ステップ1:ファイルが物理的に存在するか確認する
オートロードを疑う前に、クラスファイルが実際にディスク上に存在するか確認します:
# 実際のクラスパスに置き換えてください
find /var/www/html -name "PaymentService.php" -type f
出力がなければファイルが消えています。最初からコミットされていなかったか、削除されたか、マージされていないブランチにある可能性があります。Gitで確認できます:
git log --all --full-history -- src/Services/PaymentService.php
ファイルは存在するのにPHPが見つけられない?ステップ2に進みます。
ステップ2:名前空間がディレクトリ構造と一致しているか確認する
名前空間の不一致は、他のどの原因よりもこのエラーを引き起こします。PHPのPSR-4オートローダーは名前空間をディレクトリにマッピングします — 完全に一致していなければ、ファイルがそこにあってもPHPにはクラスが見えません。
クラスファイルを開いて宣言された名前空間を確認します:
<?php
// src/Services/PaymentService.php
namespace App\Services; // ← ディレクトリパスと一致している必要があります
class PaymentService
{
// ...
}
次にcomposer.jsonでPSR-4の設定を確認します:
{
"autoload": {
"psr-4": {
"App\\": "src/" // ← App\ は src/ にマッピングされる
}
}
}
この設定では、App\Services\PaymentServiceはsrc/Services/PaymentService.phpに配置されている必要があります。よくある3つの不一致パターンがあります:
- ファイルが
src/services/PaymentService.php(小文字のs)にある — Linuxのファイルシステムは大文字小文字を区別しますがWindowsは区別しないため、ローカル環境では動いてもサーバーで壊れます - 名前空間が
App\Service(単数形)だがディレクトリはServices(複数形)になっている - 名前空間に反映されていない余分なフォルダ階層がパスに含まれている
名前空間を修正するかファイルを移動して合わせた後、オートローダーを再生成します。
ステップ3:Composerのオートローダーを再生成する
Composerはインストール時にクラスマップを作成してキャッシュします。新しいファイルを追加したり名前空間を変更したりした後に再生成しなければ、PHPはそのクラスの存在を知りません。
# 標準的な再生成
composer dump-autoload
# 本番環境向けに最適化(全クラスのクラスマップを作成)
composer dump-autoload --optimize
# 何が登録されているか確認したい場合は生成ファイルを確認
cat vendor/composer/autoload_psr4.php
dump-autoloadを実行してページをリロードします。エラーが消えましたか?古いオートロードキャッシュが原因でした — 修正に3秒しかかからないのに、気づかないと何時間も無駄にします。
ステップ4:使用側クラスのuse文を確認する
ファイルが正しく名前空間も有効でも、use文にタイポがあれば意味がありません:
<?php
namespace App\Controllers;
// 間違い — 複数形ではなく単数形
use App\Service\PaymentService;
// 正しい
use App\Services\PaymentService;
class CheckoutController
{
public function checkout()
{
$payment = new PaymentService(); // Class 'App\Service\PaymentService' not found
}
}
use文が完全に抜けている場合にも注意が必要です。インポートがなければ、PHPは現在の名前空間でクラスを探して失敗します:
<?php
namespace App\Controllers;
// 抜けている: use Carbon\Carbon;
class ReportController
{
public function generate()
{
$date = new Carbon(); // Fatal error: Class 'App\Controllers\Carbon' not found
}
}
ステップ5:Composerを使わないプロジェクトでは手動requireのパスを確認する
レガシーコードベース、カスタムフレームワーク、Composerなし?クラスファイルは使用前に明示的にrequireされている必要があります:
<?php
// MyClassを使用する前に
require_once __DIR__ . '/../lib/MyClass.php';
$obj = new MyClass();
あるいは、require_onceを至る所に書かなくて済むよう、手動オートローダーを設定します:
<?php
spl_autoload_register(function ($className) {
$file = __DIR__ . '/lib/' . str_replace('\\', '/', $className) . '.php';
if (file_exists($file)) {
require_once $file;
}
});
ステップ6:インストール後にベンダーパッケージのクラスが見つからない
見つからないクラスがStripe、Guzzle、Monologなどのパッケージに属する場合、原因はたいていパッケージがインストールされていないか、vendor/ディレクトリがサーバーに届いていないことです:
# パッケージが実際に登録されているか確認
composer show | grep stripe
# ない場合はインストール
composer require stripe/stripe-php
# vendor/ が不完全な場合(FTP転送の途中終了、デプロイの部分完了)
composer install --no-dev
FTPデプロイでこの問題はよく起こります。アプリファイルをアップロードしてvendor/を忘れ、なぜ本番環境が壊れているのか首をかしげるパターンです。vendor/ディレクトリ全体をデプロイするか、サーバー上で直接composer installを実行してください。
修正を確認する
すぐブラウザで確認するのはやめましょう。まずCLIからテストします — Webフレームワークのノイズなしにクリーンなエラーが表示されます:
# クラスを直接インスタンス化してみる
php -r "require 'vendor/autoload.php'; new App\\Services\\PaymentService();"
# またはリフレクションを使ってPHPがロードできるか確認する
php -r "
require 'vendor/autoload.php';
if (class_exists('App\\Services\\PaymentService')) {
echo 'Class found OK' . PHP_EOL;
} else {
echo 'Still not found' . PHP_EOL;
}
"
Class found OKが表示されれば成功です。それ以外の場合は名前空間またはファイルパスがまだ間違っています。
クイックリファレンスチェックリスト
- ファイルが期待されるパスに物理的に存在する:
findまたはlsで確認 - ファイル内の名前空間が
composer.jsonのPSR-4マッピングと一致している - ディレクトリとファイル名の大文字小文字が名前空間と完全に一致している(Linuxでは要注意)
- 呼び出し元ファイルの
use文が正しく、かつ存在している - ファイルまたは名前空間の変更後に
composer dump-autoloadを実行した - サーバー上の
vendor/ディレクトリが完全かつ最新の状態である
深夜2時の呼び出しを生むパターン
真夜中のインシデントのほぼすべては、3つのうちのどれかに行き着きます。vendor/を含めなかったデプロイ。Linuxでのみ表面化する大文字小文字の不一致。またはdump-autoloadの実行を忘れた名前空間の変更。
3つすべての修正策:デプロイスクリプトにcomposer dump-autoload --optimizeを追加してください。たった1行で、この種のインシデント全体を永続的に排除できます。

