PHP 프로젝트를 관리하다 보면 Composer를 사용해서 의존성을 설치한 후에도 갑자기 'Class not found' 에러가 발생하곤 한다. 특히 네임스페이스를 사용하는 라이브러리를 새로 추가했을 때나, 프로젝트 구조를 변경한 후에 이런 문제를 자주 마주친다. 다만 대부분의 개발자들은 Composer의 오토로드 메커니즘이 정확히 어떻게 동작하는지 모른 채 인터넷에서 가져온 해결책을 무작정 따라 한다. 이번에는 Composer 오토로드가 뭔지, 왜 작동 안 되는지, 어떻게 고치는지 완벽하게 정리해서 소개하겠다.

 

Composer 오토로드의 기초 개념

Composer는 PHP의 의존성 관리 도구인데, 단순히 라이브러리를 다운로드하는 것만 하는 게 아니다. Composer는 다운로드한 모든 패키지의 클래스 위치를 맵핑하는 오토로드 파일을 자동으로 생성한다. 이 파일이 바로 vendor/autoload.php인데, 이것을 프로젝트의 진입점에서 한 번만 include 또는 require 하면 이후의 모든 클래스 호출이 자동으로 처리된다.

오토로드가 제대로 작동하려면 두 가지 조건이 필요하다. 첫째, vendor/autoload.php가 실제로 존재해야 한다. 둘째, 클래스의 네임스페이스와 파일 경로가 PSR-4 표준을 따라야 한다. PSR-4는 PHP Framework Interop Group에서 정한 표준으로, 네임스페이스와 파일 시스템 경로를 일대일 대응시키는 규칙이다. 예를 들어 App\Controller\UserController 네임스페이스는 src/Controller/UserController.php 파일 위치와 매칭된다.

 

Class not found 에러가 발생하는 주요 원인들

 

1. vendor/autoload.php를 include하지 않음

✗ 가장 흔한 실수다. Composer를 설치했지만 프로젝트 진입점(보통 index.php)에서 vendor/autoload.php를 로드하지 않으면 오토로드가 작동하지 않는다.

<?php
// ✗ 잘못된 코드
namespace App;

class MyApp {
    public function start() {
        echo "Hello";
    }
}

$app = new MyApp();
?>

위 코드에서 만약 외부 라이브러리를 사용하려 한다면 Class not found 에러가 난다. 이유는 vendor/autoload.php를 로드하지 않았기 때문이다.

✓ 올바른 코드:

<?php
require_once __DIR__ . '/vendor/autoload.php';

namespace App;

use SomeVendor\Library\SomeClass;

$instance = new SomeClass();
?>

vendor/autoload.php를 맨 위에서 로드해야 한다. __DIR__ 상수를 사용하면 현재 파일의 디렉토리를 기준으로 상대 경로를 구성할 수 있어서 이식성이 높다.

 

2. composer.json의 PSR-4 설정 오류

✗ 자신의 프로젝트 클래스를 오토로드하려면 composer.json에 PSR-4 규칙을 명시해야 한다. 이 설정을 빠뜨리거나 잘못 작성하면 문제가 생긴다.

{
    "autoload": {
        "psr-4": {
            "App\\": "src"  // 잘못된 경로 지정
        }
    }
}

위의 경우 실제로는 src/ 디렉토리에 클래스가 있는데, 오토로더가 다른 경로를 찾아서 에러가 난다.

✓ 올바른 설정:

{
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    }
}

composer.json을 수정한 후에는 반드시 composer dump-autoload 명령어를 실행해야 vendor/autoload.php 파일이 재생성된다.

 

3. composer dump-autoload를 실행하지 않음

✗ composer.json을 수정했거나 새 라이브러리를 설치한 후에 composer update를 실행하지 않으면, vendor/autoload.php가 최신 상태가 아니다.

# ✗ 잘못된 순서
echo '{"autoload": {"psr-4": {"App\\": "src/"}}}' > composer.json
php index.php  # 여전히 에러 발생

✓ 올바른 순서:

echo '{"autoload": {"psr-4": {"App\\": "src/"}}}' > composer.json
composer dump-autoload  # 또는 composer update
php index.php  # 이제 정상 작동

composer dump-autoload는 vendor/autoload.php를 재생성한다. composer install이나 composer update와 달리, 패키지를 다시 다운로드하지 않고 오토로드 맵만 갱신한다.

 

4. 네임스페이스와 파일 경로 불일치

✗ PSR-4 표준에서는 네임스페이스와 파일 경로가 정확히 매칭되어야 한다. 예를 들어 App\Controller\UserController는 src/Controller/UserController.php여야 한다. 만약 src/controller/usercontroller.php처럼 다르게 작성하면 오토로드가 실패한다.

// ✗ 파일 위치: src/controller/UserController.php (잘못된 디렉토리명 소문자)
namespace App\Controller;

class UserController {}

// index.php에서
require_once __DIR__ . '/vendor/autoload.php';
use App\Controller\UserController;  // 여전히 못 찾음
$user = new UserController();

✓ 올바른 구조:

// 파일 위치: src/Controller/UserController.php (디렉토리명 정확히 매칭)
namespace App\Controller;

class UserController {}

// index.php에서
require_once __DIR__ . '/vendor/autoload.php';
use App\Controller\UserController;  // 정상 작동
$user = new UserController();

네임스페이스의 각 부분이 디렉토리 계층과 정확히 대응되어야 한다는 점을 반드시 기억하자. 대소문자도 구분된다.

 

실전 예제: 프로젝트 구조 올바르게 설정하기

아래는 일반적인 PHP 프로젝트 구조와 올바른 Composer 설정이다.

project/
├── src/
│   ├── Controller/
│   │   └── UserController.php
│   ├── Model/
│   │   └── User.php
│   └── Service/
│       └── UserService.php
├── vendor/
├── composer.json
└── index.php

 

composer.json 설정:

{
    "name": "myproject/app",
    "description": "My PHP Application",
    "require": {
        "php": "^8.0"
    },
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    }
}

 

src/Controller/UserController.php:

<?php
namespace App\Controller;

use App\Service\UserService;

class UserController {
    private $userService;

    public function __construct() {
        $this->userService = new UserService();
    }

    public function index() {
        return "User Controller";
    }
}

 

src/Service/UserService.php:

<?php
namespace App\Service;

use App\Model\User;

class UserService {
    public function getUser($id) {
        $user = new User();
        $user->setId($id);
        return $user;
    }
}

 

index.php (진입점):

<?php
require_once __DIR__ . '/vendor/autoload.php';

use App\Controller\UserController;

$controller = new UserController();
echo $controller->index();
?>

 

이 구조에서 Composer 설정을 완료한 후 다음 명령어를 실행한다.

composer dump-autoload

이제 index.php를 실행하면 UserController가 자동으로 로드되고, UserController 생성자에서 UserService가 필요하면 그것도 자동으로 로드된다.

 

문제 해결 체크리스트

 

확인 항목 해결 방법
vendor/autoload.php가 존재하지 않음 composer install 또는 composer update 실행
프로젝트 진입점에 require_once를 작성하지 않음 index.php 맨 위에 require_once __DIR__ . '/vendor/autoload.php'; 추가
composer.json의 PSR-4 설정이 없음 또는 잘못됨 composer.json의 autoload 섹션 확인 및 수정
composer.json을 수정했지만 dump-autoload를 실행하지 않음 composer dump-autoload 또는 composer update 실행
네임스페이스와 파일 경로가 불일치 네임스페이스 계층과 디렉토리 구조를 정확히 맞춤
캐시 문제로 인해 여전히 작동 안 함 vendor/autoload.php 및 vendor/composer 디렉토리 삭제 후 composer install 재실행

 

고급: Composer의 여러 오토로드 방식

PSR-4 외에도 Composer는 여러 오토로드 전략을 지원한다. 대부분의 경우 PSR-4를 사용하지만, 레거시 프로젝트에서는 다른 방식이 필요할 수도 있다.

{
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        },
        "psr-0": {
            "Legacy_": "lib/"
        },
        "classmap": [
            "src/Helpers.php",
            "src/Utilities/"
        ],
        "files": [
            "src/helpers.php",
            "src/functions.php"
        ]
    }
}

PSR-0는 오래된 표준이고, classmap은 특정 클래스 파일을 명시적으로 등록한다. files는 함수 모음 파일처럼 클래스가 아닌 코드를 매 요청마다 로드할 때 사용한다. 하지만 현대적인 프로젝트에서는 PSR-4만으로 충분하다.

 

마무리

Composer의 오토로드는 PHP 개발의 필수 요소다. vendor/autoload.php를 로드하는 것 하나만으로도 프로젝트의 대부분의 클래스를 자동으로 관리할 수 있다. PSR-4 표준을 따르고 네임스페이스와 파일 경로를 정확히 맞추는 것이 핵심이다. Class not found 에러를 만났을 때는 이 글의 체크리스트를 차례대로 확인해보면, 거의 모든 경우 문제를 해결할 수 있을 것이다.