What's Actually Happening
Your PHP application crashes with a fatal error indicating that a class cannot be found. This happens when PHP's autoloader fails to locate the class file, when namespaces are incorrectly mapped, when Composer's autoload files haven't been regenerated after adding new classes, when the class file exists but has a different name than expected by the autoloader, or when the autoload configuration doesn't match your actual directory structure.
The error prevents your application from starting or executing specific features. In development, you see the error immediately. In production with caching, the error might appear intermittently or after cache clears. This issue commonly occurs after adding new classes, moving files, refactoring namespaces, updating Composer packages, or deploying to new environments.
The Error You'll See
``` Fatal error: Uncaught Error: Class "App\Services\UserService" not found in /var/www/html/controllers/UserController.php:23
Fatal error: Class 'UserService' not found in /var/www/app/index.php on line 45
Error: Class "GuzzleHttp\Client" not found in /var/www/api/HttpClient.php:12
Fatal error: Uncaught Error: Class not found: App\Models\Product Stack trace: #0 /var/www/html/index.php(45): spl_autoload_call('App\Models\Product') #1 {main} thrown in /var/www/html/index.php on line 45
PHP Fatal error: Class 'Symfony\Component\HttpFoundation\Request' not found in /var/www/bootstrap.php on line 34
Fatal error: Interface 'App\Contracts\RepositoryInterface' not found in /var/www/app/Repositories/UserRepository.php:8
Error: Class "Monolog\Logger" not found
[08-Apr-2026 16:00:12 UTC] PHP Fatal error: Uncaught Error: Class "App\Services\PaymentService" not found in /var/www/app/Controllers/PaymentController.php:23 Stack trace: #0 /var/www/app/Controllers/PaymentController.php(23): spl_autoload_call('App\\Services\\PaymentService') #1 /var/www/public/index.php(15): App\Controllers\PaymentController->processPayment() #2 {main} thrown ```
When running Composer commands:
``` Class App\Services\UserService located in ./app/Services/userService.php does not comply with psr-4 autoloading standard. Skipping.
Class App\Models\Product is not autoloadable, cannot generate autoload files
Warning: Class App\Controller\UserController located in /var/www/app/Controllers/User/Controller.php does not match expected location
Cannot autoload class: file not found for namespace ```
Why This Happens
- 1.Missing Composer autoload dump: After adding new classes or changing directory structure, you must regenerate the autoload files with
composer dump-autoload. Without this, Composer's class map doesn't know about your new classes. - 2.Namespace mismatch: The namespace declared inside your PHP file doesn't match the PSR-4 mapping in composer.json, or the namespace declaration is missing entirely from the class file.
- 3.Incorrect file naming: PSR-4 autoloading expects the class file name to match the class name exactly.
UserServiceclass should be inUserService.php, notuserService.phporuser_service.php. - 4.Wrong directory structure: Your files are in directories that don't match the namespace structure. If namespace is
App\Services, the file should be insrc/Services/directory (assuming PSR-4 mapping forApptosrc/). - 5.Missing vendor directory: The vendor directory with autoload files doesn't exist (never ran
composer install) or was deleted accidentally, or wasn't deployed to production. - 6.Case sensitivity issues: On Linux systems, file names are case-sensitive.
UserService.phpanduserService.phpare different files. Windows and macOS are case-insensitive, causing issues when deploying to Linux servers. - 7.Autoload configuration errors: The composer.json autoload section has incorrect paths, wrong namespace prefixes, or uses the wrong autoloading standard (PSR-0 vs PSR-4).
- 8.Missing use statements: You're trying to use a class without importing it with a
usestatement, relying on PHP's global namespace where the class doesn't exist. - 9.Extension not loaded: The class is provided by a PHP extension that isn't installed or enabled, like PDO classes without PDO extension, or Composer classes without Composer autoload loaded.
- 10.Stale opcache: PHP's opcode cache has cached an old version of the autoload file or class map, and needs to be cleared after updates.
Step 1: Verify Composer Autoload Configuration
Check your composer.json autoload configuration:
```bash # View current autoload configuration cat composer.json | grep -A 20 "autoload"
# Check if vendor/autoload.php exists ls -la vendor/autoload.php ls -la vendor/composer/autoload_*.php
# Verify autoload files are loaded in your bootstrap grep -rn "autoload.php" public/index.php bootstrap.php app.php
# Common correct autoload configuration cat > /tmp/autoload_example.json << 'EOF' { "autoload": { "psr-4": { "App\\": "src/", "App\\Models\\": "src/Models/", "App\\Services\\": "src/Services/", "App\\Controllers\\": "src/Controllers/" }, "classmap": [ "database/seeds/", "database/factories/" ], "files": [ "app/helpers.php", "src/functions.php" ] }, "autoload-dev": { "psr-4": { "Tests\\": "tests/" } } } EOF
# Check your actual configuration php -r "echo json_encode(json_decode(file_get_contents('composer.json'))->autoload, JSON_PRETTY_PRINT);"
# Check autoload_classmap.php to see registered classes php -r "var_export(require 'vendor/composer/autoload_classmap.php');" ```
Verify your bootstrap file loads the autoloader:
```php <?php // public/index.php or bootstrap.php
// This must be the first thing loaded require_once __DIR__ . '/../vendor/autoload.php';
// Verify autoload is loaded if (!file_exists(__DIR__ . '/../vendor/autoload.php')) { die('Composer autoload not found. Run: composer install'); }
// Check if a specific class can be loaded if (!class_exists('App\Services\UserService')) { die('UserService class not found. Check namespace and file location.'); }
// Start your application $app = new App\Application(); $app->run(); ?> ```
Step 2: Regenerate Autoload Files
The most common fix is to regenerate the autoload files:
```bash # Basic autoload regeneration composer dump-autoload
# With optimization (faster in production) composer dump-autoload --optimize composer dump-autoload -o
# For production (optimized, no dev autoload) composer dump-autoload --optimize --no-dev composer dump-autoload -o --no-dev
# If autoload is completely broken, regenerate from scratch rm -rf vendor/composer/autoload_*.php composer dump-autoload
# Full reinstall if vendor directory is corrupted rm -rf vendor/ composer install --no-dev --optimize-autoloader
# Check generated files after dump ls -la vendor/composer/ cat vendor/composer/autoload_classmap.php | head -50 cat vendor/composer/autoload_psr4.php
# Verify specific class is in classmap grep "UserService" vendor/composer/autoload_classmap.php grep -r "App\\\\Services\\\\UserService" vendor/composer/
# Check autoload statistics composer dump-autoload --optimize --stats ```
Create a script to automate autoload regeneration during deployment:
```bash #!/bin/bash # deploy.sh - Part of deployment process
echo "Regenerating autoload files..."
# Remove old autoload files rm -f vendor/composer/autoload_classmap.php rm -f vendor/composer/autoload_psr4.php rm -f vendor/composer/autoload_static.php rm -f vendor/composer/autoload_files.php
# Regenerate with optimization composer dump-autoload --optimize --no-dev
# Verify critical classes are loaded echo "Verifying autoload..." php -r " require 'vendor/autoload.php'; \$classes = ['App\Services\UserService', 'App\Models\User', 'App\Controllers\HomeController']; foreach (\$classes as \$class) { if (!class_exists(\$class)) { echo 'Missing: ' . \$class . PHP_EOL; exit(1); } } echo 'All classes loaded successfully' . PHP_EOL; "
if [ $? -eq 0 ]; then echo "Autoload regeneration successful" else echo "Autoload verification failed" exit 1 fi
# Clear PHP opcache if applicable if [ -f "/etc/php/*/fpm/conf.d/10-opcache.ini" ]; then echo "Clearing opcache..." php -r "if(function_exists('opcache_reset')) opcache_reset();" fi ```
Step 3: Fix Namespace and Directory Structure
Ensure namespaces match your directory structure according to PSR-4:
```bash # PSR-4: Namespace prefix maps to base directory # App\Services\UserService -> src/Services/UserService.php
# Check directory structure find src/ -name "*.php" -type f | head -20
# Verify namespace declarations in files grep -rn "namespace App" src/ | head -20
# Check for namespace mismatches for file in src/**/*.php; do expected_namespace=$(dirname "$file" | sed 's|src/|App\|' | sed 's|/|\|g') actual_namespace=$(grep "^namespace" "$file" | head -1) echo "File: $file" echo "Expected namespace: $expected_namespace" echo "Actual namespace: $actual_namespace" echo "---" done
# Fix common namespace issues # Example: src/Services/UserService.php should have: cat > src/Services/UserService.php << 'EOF' <?php
namespace App\Services;
class UserService { public function getUser($id) { // Implementation } } EOF
# Verify the class matches expected location cat > /tmp/verify_namespace.php << 'EOF' <?php // Verify namespace matches file location
$classMap = require __DIR__ . '/vendor/composer/autoload_classmap.php'; $psr4Map = require __DIR__ . '/vendor/composer/autoload_psr4.php';
$errors = [];
foreach ($classMap as $class => $file) { // Extract expected path from namespace $parts = explode('\\', $class); $className = end($parts); $expectedFile = $className . '.php';
$actualFile = basename($file);
if ($actualFile !== $expectedFile) { $errors[] = [ 'class' => $class, 'expected_file' => $expectedFile, 'actual_file' => $actualFile, 'location' => $file ]; } }
if (empty($errors)) { echo "All namespace mappings are correct\n"; } else { echo "Namespace mapping errors:\n"; foreach ($errors as $error) { echo "Class: {$error['class']}\n"; echo "Expected file: {$error['expected_file']}\n"; echo "Actual file: {$error['actual_file']}\n"; echo "Location: {$error['location']}\n\n"; } } EOF
php /tmp/verify_namespace.php ```
Fix specific namespace issues:
```php <?php // WRONG: Missing namespace // File: src/Services/UserService.php class UserService // No namespace - will not autoload correctly { // Class body }
// WRONG: Namespace doesn't match PSR-4 mapping // File: src/Services/UserService.php namespace Services; // Should be App\Services class UserService {}
// WRONG: Wrong case in namespace // File: src/Services/UserService.php namespace App\services; // Should be App\Services (case-sensitive!) class UserService {}
// CORRECT: Namespace matches PSR-4 // composer.json: "App\\" => "src/" // File: src/Services/UserService.php namespace App\Services;
class UserService { // Implementation }
// CORRECT: Nested namespace // composer.json: "App\\" => "src/" // File: src/Services/Payment/StripeService.php namespace App\Services\Payment;
class StripeService { // Implementation }
// CORRECT: Multiple namespace levels // File: src/Models/Entities/User.php namespace App\Models\Entities;
class User { protected $id; protected $name; } ?> ```
Step 4: Fix File Naming Case Sensitivity
Ensure file names exactly match class names:
```bash # List all PHP files and check case find src/ -name "*.php" -exec basename {} \; | sort
# Check for case mismatches between file name and class name cat > /tmp/check_case.php << 'EOF' <?php // Check file naming case sensitivity
$directory = new RecursiveDirectoryIterator('src'); $iterator = new RecursiveIteratorIterator($directory);
$errors = [];
foreach ($iterator as $file) { if ($file->getExtension() !== 'php') continue;
$filename = $file->getBasename('.php'); $path = $file->getPathname();
// Read file and extract class name $content = file_get_contents($path);
// Find class declaration if (preg_match('/class\s+(\w+)/', $content, $matches)) { $className = $matches[1];
// Compare file name and class name if ($filename !== $className) { $errors[] = [ 'file' => $path, 'filename' => $filename, 'classname' => $className, 'issue' => 'File name does not match class name' ]; } } }
if (empty($errors)) { echo "All files match their class names\n"; } else { echo "File naming errors:\n"; foreach ($errors as $error) { echo sprintf( "File: %s\nFilename: %s\nClassname: %s\nIssue: %s\n\n", $error['file'], $error['filename'], $error['classname'], $error['issue'] ); } } EOF
php /tmp/check_case.php
# Fix case mismatches by renaming files # Example: rename userService.php to UserService.php mv src/Services/userService.php src/Services/UserService.php
# Batch fix script cat > /tmp/fix_case.sh << 'EOF' #!/bin/bash
# Find and fix case mismatches for file in $(find src -name "*.php"); do filename=$(basename "$file" .php) classname=$(grep -Po 'class\s+\K\w+' "$file" | head -1)
if [ "$filename" != "$classname" ] && [ ! -z "$classname" ]; then echo "Fixing: $file" echo "Filename: $filename -> Classname: $classname"
dir=$(dirname "$file") mv "$file" "$dir/$classname.php" fi done
echo "Files renamed. Run: composer dump-autoload" EOF
chmod +x /tmp/fix_case.sh /tmp/fix_case.sh composer dump-autoload --optimize ```
Step 5: Add Missing Use Statements
Import classes that you're trying to use:
```php <?php // WRONG: Using class without importing // File: src/Controllers/UserController.php namespace App\Controllers;
class UserController { public function show($id) { // UserService is not imported! $service = new UserService(); // Error: Class not found return $service->getUser($id); } }
// CORRECT: Import the class namespace App\Controllers;
use App\Services\UserService; // Import statement use App\Models\User;
class UserController { public function show($id) { $service = new UserService(); // Now works return $service->getUser($id); } }
// CORRECT: Import multiple classes namespace App\Controllers;
use App\Services\UserService; use App\Services\EmailService; use App\Services\AuthService; use App\Models\User; use App\Models\Profile;
class UserController extends BaseController { protected $userService; protected $emailService;
public function __construct( UserService $userService, EmailService $emailService ) { $this->userService = $userService; $this->emailService = $emailService; } }
// CORRECT: Import with alias to avoid conflicts namespace App\Controllers;
use App\Services\UserService as US; use External\Lib\UserService as ExternalUserService;
class UserController { public function index() { $localService = new US(); $externalService = new ExternalUserService(); } }
// CORRECT: Group use statements (PHP 7+) namespace App\Controllers;
use App\Services\{UserService, EmailService, AuthService}; use App\Models\{User, Profile, Settings};
class UserController { // Use all imported classes }
// CORRECT: Import interfaces and traits namespace App\Repositories;
use App\Contracts\RepositoryInterface; use App\Traits\LoggableTrait;
class UserRepository implements RepositoryInterface { use LoggableTrait;
// Implementation }
// CORRECT: Import functions and constants namespace App\Utils;
use function App\Helpers\formatDate; use const App\Config\MAX_ITEMS;
class Formatter { public function format($date) { return formatDate($date); } } ?> ```
Find missing use statements in your codebase:
```bash # Find classes used without import grep -rn "new [A-Z][a-zA-Z]*(" src/ --include="*.php" | grep -v "use " | head -30
# Find method calls on unknown classes grep -rn "::[a-zA-Z]*(" src/ --include="*.php" | grep -v "use " | head -20
# Find extends/implements without import grep -rn "extends [A-Z]" src/ --include="*.php" | grep -v "use " grep -rn "implements [A-Z]" src/ --include="*.php" | grep -v "use "
# Create script to find missing imports cat > /tmp/find_missing_imports.php << 'EOF' <?php $directory = 'src'; $iterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($directory) );
$missingImports = [];
foreach ($iterator as $file) { if ($file->getExtension() !== 'php') continue;
$content = file_get_contents($file->getPathname());
// Get declared namespace $namespace = ''; if (preg_match('/namespace\s+([^;]+);/', $content, $m)) { $namespace = trim($m[1]); }
// Get imported classes $imports = []; preg_match_all('/use\s+([^;]+);/', $content, $matches); foreach ($matches[1] as $import) { // Handle grouped imports if (strpos($import, '{') !== false) { // Parse grouped import preg_match('/([^{]+)\{([^}]+)\}/', $import, $group); $base = trim($group[1]); $classes = explode(',', $group[2]); foreach ($classes as $class) { $imports[] = trim($base . trim($class)); } } else { $imports[] = trim($import); } }
// Find class instantiations preg_match_all('/new\s+([A-Z][a-zA-Z0-9_\\\]*)\s*\(/', $content, $instantiations);
foreach ($instantiations[1] as $className) { // Skip if fully qualified (starts with \) if (strpos($className, '\\') === 0) continue;
// Skip if in same namespace if ($namespace && strpos($className, $namespace) === 0) continue;
// Check if imported $imported = false; foreach ($imports as $import) { $parts = explode('\\', $import); $importName = end($parts); if ($importName === $className || $import === $className) { $imported = true; break; } }
if (!$imported && !in_array($className, ['self', 'static', 'parent'])) { $missingImports[] = [ 'file' => $file->getPathname(), 'class' => $className, 'line' => 0 // Would need more parsing for exact line ]; } } }
echo "Missing imports found:\n"; foreach ($missingImports as $missing) { echo "File: {$missing['file']}\n"; echo "Class: {$missing['class']}\n\n"; } EOF
php /tmp/find_missing_imports.php ```
Step 6: Fix Third-Party Package Class Issues
Handle missing classes from Composer packages:
```bash # Check if package is installed composer show guzzlehttp/guzzle composer show monolog/monolog composer show symfony/http-foundation
# List all installed packages composer show
# Check package autoload configuration composer show guzzlehttp/guzzle | grep -A 5 "autoload"
# If package is missing, install it composer require guzzlehttp/guzzle composer require monolog/monolog composer require symfony/http-foundation
# Update packages to get latest versions composer update guzzlehttp/guzzle
# Check vendor directory for package files ls -la vendor/guzzlehttp/guzzle/src/ ls -la vendor/monolog/monolog/src/Monolog/
# Verify package class can be loaded php -r " require 'vendor/autoload.php'; if (class_exists('GuzzleHttp\Client')) { echo 'GuzzleHttp\\Client loaded successfully\n'; } else { echo 'GuzzleHttp\\Client NOT found\n'; } "
# Check for package conflicts or version issues composer why-not guzzlehttp/guzzle 7.0
# Diagnose autoload issues composer diagnose ```
Fix package-specific autoload issues:
```php <?php // bootstrap.php - Ensure packages are loaded
require_once __DIR__ . '/vendor/autoload.php';
// Check critical packages $requiredPackages = [ 'GuzzleHttp\Client' => 'guzzlehttp/guzzle', 'Monolog\Logger' => 'monolog/monolog', 'Symfony\Component\HttpFoundation\Request' => 'symfony/http-foundation', 'Doctrine\ORM\EntityManager' => 'doctrine/orm', ];
$missing = []; foreach ($requiredPackages as $class => $package) { if (!class_exists($class)) { $missing[$class] = $package; } }
if (!empty($missing)) { $missingPackages = implode(', ', array_values($missing)); die("Missing packages: $missingPackages. Run: composer require " . implode(' ', array_values($missing))); }
// Verify package version compatibility if (class_exists('GuzzleHttp\Client')) { $version = GuzzleHttp\Client::MAJOR_VERSION ?? null; if ($version && $version < 7) { die('Guzzle version 7+ required. Current: ' . $version); } }
// Handle packages with custom bootstrapping if (class_exists('Doctrine\ORM\EntityManager')) { // Doctrine requires additional setup $entityManager = Doctrine\ORM\EntityManager::create( $dbParams, $config ); } ?> ```
Step 7: Configure Classmap for Non-PSR-4 Classes
Use classmap for legacy code or non-standard naming:
{
"autoload": {
"psr-4": {
"App\\": "src/"
},
"classmap": [
"legacy/",
"app/old_classes/",
"database/"
],
"files": [
"app/helpers.php",
"legacy/functions.php"
]
}
}```bash # After adding to classmap, regenerate autoload composer dump-autoload --optimize
# Verify classmap loaded classes php -r "var_export(array_keys(require 'vendor/composer/autoload_classmap.php'));"
# Check if specific legacy class is loaded grep "LegacyClass" vendor/composer/autoload_classmap.php
# Add specific files to classmap manually if needed composer dump-autoload --classmap-authoritative ```
Handle legacy code patterns:
```php <?php // legacy/UserService.php - Non PSR-4 compliant // No namespace, or different namespace than directory structure
// This file won't autoload with PSR-4 // Add to composer.json classmap or files section
// Option 1: Add to classmap in composer.json // "classmap": ["legacy/UserService.php"]
// Option 2: Add to files section (always loaded) // "files": ["legacy/functions.php", "legacy/UserService.php"]
// Option 3: Convert to PSR-4 // Move file to src/Legacy/UserService.php // Add namespace App\Legacy;
// legacy/UserService.php converted: namespace App\Legacy;
class UserService { // Legacy implementation }
// Now autoloads with: new App\Legacy\UserService();
// Hybrid approach: Keep legacy, add modern wrapper namespace App\Services;
use App\Legacy\UserService as LegacyUserService;
class UserServiceWrapper { private $legacyService;
public function __construct() { $this->legacyService = new LegacyUserService(); }
public function getUser($id) { return $this->legacyService->findUser($id); } } ?> ```
Step 8: Clear PHP Opcode Cache
Clear opcache after autoload updates:
```php <?php // Clear opcache via PHP script if (function_exists('opcache_reset')) { opcache_reset(); echo "Opcache cleared successfully"; } else { echo "Opcache not available"; }
// Clear specific files from opcache if (function_exists('opcache_invalidate')) { $filesToClear = [ __DIR__ . '/vendor/composer/autoload_classmap.php', __DIR__ . '/vendor/composer/autoload_psr4.php', __DIR__ . '/vendor/composer/autoload_static.php', __DIR__ . '/vendor/autoload.php', ];
foreach ($filesToClear as $file) { if (opcache_invalidate($file, true)) { echo "Cleared: $file\n"; } } }
// Force reload of autoload files require_once __DIR__ . '/vendor/autoload.php'; ?> ```
```bash # Clear opcache via PHP-FPM sudo service php8.2-fpm restart
# Or via FastCGI php -r " if (function_exists('opcache_reset')) { opcache_reset(); } "
# Or via web request (create clear-cache endpoint) curl "http://localhost/clear-opcache.php"
# Check opcache status php -r " if (function_exists('opcache_get_status')) { \$status = opcache_get_status(false); echo 'Opcache enabled: ' . (\$status['opcache_enabled'] ? 'yes' : 'no') . PHP_EOL; echo 'Cached scripts: ' . count(\$status['scripts'] ?? []) . PHP_EOL; } "
# Configure opcache to auto-validate changes # In php.ini or php-fpm config: # opcache.validate_timestamps=1 (development) # opcache.validate_timestamps=0 (production - must clear manually) # opcache.revalidate_freq=0 (check every request, development) # opcache.revalidate_freq=60 (check every 60s, production) ```
Create an opcache management script:
```php <?php // public/clear-opcache.php - Restricted access
// Restrict to CLI or authenticated users if (php_sapi_name() !== 'cli') { // Check authentication token $token = $_GET['token'] ?? ''; $expectedToken = getenv('OPCACHE_CLEAR_TOKEN');
if (!$expectedToken || $token !== $expectedToken) { http_response_code(403); exit('Access denied'); } }
header('Content-Type: application/json');
$result = [ 'opcache_available' => function_exists('opcache_reset'), 'actions' => [] ];
if ($result['opcache_available']) { // Full reset $result['actions']['reset'] = opcache_reset();
// Invalidate autoload files specifically $autoloadFiles = [ realpath(__DIR__ . '/../vendor/autoload.php'), realpath(__DIR__ . '/../vendor/composer/autoload_classmap.php'), realpath(__DIR__ . '/../vendor/composer/autoload_psr4.php'), realpath(__DIR__ . '/../vendor/composer/autoload_static.php'), ];
$result['actions']['invalidated_files'] = []; foreach ($autoloadFiles as $file) { if ($file && file_exists($file)) { $result['actions']['invalidated_files'][$file] = opcache_invalidate($file, true); } }
// Get status after clearing $result['status'] = opcache_get_status(false); }
echo json_encode($result, JSON_PRETTY_PRINT); ?> ```
Step 9: Debug Autoload Issues with Custom Loader
Create debugging tools to investigate autoload failures:
```php <?php // debug_autoload.php - Autoload debugging script
// Register debug autoloader before Composer's spl_autoload_register(function($className) { $logFile = __DIR__ . '/autoload_debug.log';
$logEntry = sprintf( "[%s] Attempting to load: %s\n", date('Y-m-d H:i:s'), $className );
// Check PSR-4 mappings $mappings = [ 'App\\' => __DIR__ . '/src/', 'App\\Services\\' => __DIR__ . '/src/Services/', 'App\\Models\\' => __DIR__ . '/src/Models/', ];
foreach ($mappings as $prefix => $baseDir) { $logEntry .= " Checking prefix: $prefix => $baseDir\n";
$len = strlen($prefix); if (strncmp($prefix, $className, $len) === 0) { $relativeClass = substr($className, $len); $file = $baseDir . str_replace('\\', '/', $relativeClass) . '.php';
$logEntry .= " Expected file: $file\n"; $logEntry .= " File exists: " . (file_exists($file) ? 'YES' : 'NO') . "\n";
if (file_exists($file)) { $logEntry .= " SUCCESS: Loading file\n"; file_put_contents($logFile, $logEntry, FILE_APPEND); require $file; return true; } } }
$logEntry .= " FAILED: Class not found\n"; file_put_contents($logFile, $logEntry, FILE_APPEND);
return false; }, true, true); // prepend to autoload stack
// Now load Composer's autoloader require __DIR__ . '/vendor/autoload.php';
// Test class loading $testClasses = [ 'App\Services\UserService', 'App\Models\User', 'GuzzleHttp\Client', ];
foreach ($testClasses as $class) { echo "Testing: $class\n"; try { if (class_exists($class)) { echo " SUCCESS: Class loaded\n"; } else { echo " FAILED: Class not found\n"; } } catch (Error $e) { echo " ERROR: " . $e->getMessage() . "\n"; } }
// Check debug log echo "\nDebug log:\n"; echo file_get_contents(__DIR__ . '/autoload_debug.log'); ?>
<?php // Comprehensive autoload debugger class AutoloadDebugger { private $log = []; private $mappings = [];
public function __construct() { // Get Composer's PSR-4 mappings $autoloadFile = __DIR__ . '/vendor/composer/autoload_psr4.php'; if (file_exists($autoloadFile)) { $this->mappings = require $autoloadFile; } }
public function debug($className) { $this->log[] = "Debugging class: $className";
// Check each mapping foreach ($this->mappings as $prefix => $dirs) { $this->log[] = "Prefix: $prefix";
foreach ($dirs as $dir) { $this->log[] = " Base dir: $dir";
$relativeClass = ltrim(substr($className, strlen($prefix)), '\\'); $file = $dir . str_replace('\\', '/', $relativeClass) . '.php';
$this->log[] = " Expected file: $file"; $this->log[] = " File exists: " . (file_exists($file) ? 'YES' : 'NO');
if (file_exists($file)) { $this->checkFileContents($file, $className); } } }
return $this->log; }
private function checkFileContents($file, $expectedClass) { $content = file_get_contents($file);
$this->log[] = " Checking file contents...";
// Check namespace if (preg_match('/namespace\s+([^;]+);/', $content, $m)) { $namespace = trim($m[1]); $this->log[] = " Declared namespace: $namespace";
$fullClass = $namespace . '\\' . basename($file, '.php'); $this->log[] = " Full class name: $fullClass"; $this->log[] = " Expected class: $expectedClass"; $this->log[] = " Match: " . ($fullClass === $expectedClass ? 'YES' : 'NO - MISMATCH!'); } else { $this->log[] = " WARNING: No namespace declared!"; }
// Check class declaration if (preg_match('/class\s+(\w+)/', $content, $m)) { $this->log[] = " Class name in file: " . $m[1]; } else { $this->log[] = " WARNING: No class declaration found!"; } }
public function getLog() { return implode("\n", $this->log); } }
// Usage $debugger = new AutoloadDebugger(); $debugger->debug('App\Services\UserService'); echo $debugger->getLog(); ?> ```
Step 10: Set Up Continuous Autoload Validation
Implement automated checks for autoload issues:
```bash #!/bin/bash # scripts/check_autoload.sh - Run before deployment
echo "Checking autoload configuration..."
# Check composer.json is valid composer validate --strict
# Regenerate autoload composer dump-autoload --optimize
# Get list of classes to verify classes=( "App\\Services\\UserService" "App\\Models\\User" "App\\Controllers\\HomeController" )
# Check each class for class in "${classes[@]}"; do php -r " require 'vendor/autoload.php'; if (!class_exists('$class')) { echo 'Missing: $class' . PHP_EOL; exit(1); } echo 'Found: $class' . PHP_EOL; "
if [ $? -ne 0 ]; then echo "ERROR: Class $class not found in autoload" exit 1 fi done
# Check file naming matches class names php scripts/verify_class_names.php
# Check namespace consistency php scripts/verify_namespaces.php
echo "All autoload checks passed" ```
```php <?php // scripts/verify_class_names.php
$iterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator('src') );
$errors = [];
foreach ($iterator as $file) { if ($file->getExtension() !== 'php') continue;
$filename = $file->getBasename('.php'); $content = file_get_contents($file->getPathname());
// Extract class name if (!preg_match('/class\s+(\w+)/', $content, $match)) { continue; // No class in file }
$className = $match[1];
if ($filename !== $className) { $errors[] = [ 'file' => $file->getPathname(), 'filename' => $filename, 'className' => $className ]; } }
if (empty($errors)) { echo "All class names match file names\n"; exit(0); } else { echo "ERRORS: Class names do not match file names:\n"; foreach ($errors as $error) { echo " File: {$error['file']}\n"; echo " Filename: {$error['filename']}\n"; echo " Class: {$error['className']}\n\n"; } exit(1); } ?>
<?php // scripts/verify_namespaces.php
$iterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator('src') );
$errors = []; $expectedBase = 'App';
foreach ($iterator as $file) { if ($file->getExtension() !== 'php') continue;
$relativePath = substr($file->getPathname(), strlen('src/') + 1); $dirPath = dirname($relativePath);
// Expected namespace from path $expectedNamespace = $expectedBase; if ($dirPath !== '.' && $dirPath !== '') { $expectedNamespace .= '\\' . str_replace('/', '\\', $dirPath); }
$content = file_get_contents($file->getPathname());
// Extract declared namespace if (!preg_match('/namespace\s+([^;]+);/', $content, $match)) { $errors[] = [ 'file' => $file->getPathname(), 'expected' => $expectedNamespace, 'actual' => 'NO NAMESPACE' ]; continue; }
$actualNamespace = trim($match[1]);
if ($actualNamespace !== $expectedNamespace) { $errors[] = [ 'file' => $file->getPathname(), 'expected' => $expectedNamespace, 'actual' => $actualNamespace ]; } }
if (empty($errors)) { echo "All namespaces are consistent\n"; exit(0); } else { echo "ERRORS: Namespace inconsistencies:\n"; foreach ($errors as $error) { echo " File: {$error['file']}\n"; echo " Expected: {$error['expected']}\n"; echo " Actual: {$error['actual']}\n\n"; } exit(1); } ?> ```
Checklist
| Step | Action | Verified |
|---|---|---|
| 1 | Verified composer.json autoload configuration | ☐ |
| 2 | Regenerated autoload files with dump-autoload | ☐ |
| 3 | Fixed namespace declarations to match PSR-4 | ☐ |
| 4 | Corrected file naming case sensitivity | ☐ |
| 5 | Added missing use statements | ☐ |
| 6 | Installed missing Composer packages | ☐ |
| 7 | Configured classmap for legacy code | ☐ |
| 8 | Cleared PHP opcode cache | ☐ |
| 9 | Debugged autoload with custom loader | ☐ |
| 10 | Set up continuous autoload validation | ☐ |
| 11 | Verified vendor/autoload.php loads | ☐ |
| 12 | Tested in production environment | ☐ |
Verify the Fix
- 1.Test autoload file loading:
- 2.```bash
- 3.# Basic autoload test
- 4.php -r "
- 5.require 'vendor/autoload.php';
- 6.echo 'Autoload loaded successfully\n';
- 7."
# Test specific class loading php -r " require 'vendor/autoload.php'; \$classes = ['App\Services\UserService', 'App\Models\User']; foreach (\$classes as \$class) { echo \$class . ': ' . (class_exists(\$class) ? 'LOADED' : 'NOT FOUND') . '\n'; } " ```
- 1.Verify Composer configuration:
- 2.```bash
- 3.# Validate composer.json
- 4.composer validate --strict
# Diagnose issues composer diagnose
# Show autoload configuration composer config autoload
# Check autoload files ls -la vendor/composer/autoload_*.php ```
- 1.Test in application context:
- 2.```php
- 3.<?php
- 4.// test_application_bootstrap.php
- 5.require_once __DIR__ . '/vendor/autoload.php';
// Test core classes $coreClasses = [ 'App\Application', 'App\Services\UserService', 'App\Controllers\HomeController', ];
foreach ($coreClasses as $class) { try { $instance = new $class(); echo "SUCCESS: Created instance of $class\n"; } catch (Error $e) { echo "FAILED: $class - " . $e->getMessage() . "\n"; } } ?> ```
- 1.Check namespace mappings:
- 2.```bash
- 3.# View PSR-4 mappings
- 4.php -r "var_export(require 'vendor/composer/autoload_psr4.php');"
# View classmap php -r "print_r(array_keys(require 'vendor/composer/autoload_classmap.php'));"
# Find specific class in classmap grep "UserService" vendor/composer/autoload_classmap.php ```
- 1.Run automated verification:
- 2.```bash
- 3.# Run check script
- 4../scripts/check_autoload.sh
# Run namespace verification php scripts/verify_namespaces.php
# Run class name verification php scripts/verify_class_names.php ```
- 1.Monitor after deployment:
- 2.```bash
- 3.# Watch for class not found errors
- 4.tail -f /var/log/php-fpm/error.log | grep "Class.*not found"
# Check error rate grep -c "Class.*not found" /var/log/php-fpm/error.log
# Clear and monitor truncate -s 0 /var/log/php-fpm/error.log # Test application curl http://localhost/ grep "Class" /var/log/php-fpm/error.log ```
Related Issues
- [Fix PHP Composer Dependency Conflict](/articles/fix-php-composer-dependency-conflict)
- [Fix PHP Composer Out of Memory](/articles/fix-php-composer-out-of-memory)
- [Fix PHP Namespace Declaration Error](/articles/fix-php-namespace-declaration-error)
- [Fix Laravel Model Not Found](/articles/fix-laravel-model-not-found)
- [Fix Symfony Service Not Found](/articles/fix-symfony-service-not-found)
- [Fix WordPress Plugin Class Not Found](/articles/fix-wordpress-plugin-class-not-found)
- [Fix PHP Type Error Argument Mismatch](/articles/fix-php-type-error-argument-mismatch)
- [Fix PHP Interface Not Found](/articles/fix-php-interface-not-found)
- [Fix Magento Module Class Missing](/articles/fix-magento-module-class-missing)
- [Fix Drupal Module Class Not Loaded](/articles/fix-drupal-module-class-not-loaded)