PHP에서 소스를 include하여 재사용하는 올바른 코딩 방법

프로그램을 개발 할때 올바른 코딩이란, 코드의 동작을 목표로하는 것 보다는 

코드블럭을 나누고 재사용할 수 있는 코드는 include 해서 수정과 유지관리에 편리성과 가독성 그리고 확장성을

고려해야 합니다. PHP에서 소스를 include하여 재사용하는 올바른 코딩 방법을 정리해드리겠습니다.

 

📌 핵심 요약

1️⃣ 언제 무엇을 사용할까?

  • require_once: 설정 파일, 클래스, 필수 함수
  • include: 템플릿 파일 (header, footer)
  • require: 없으면 치명적인 파일
  • include_once: 거의 사용 안 함 (require_once로 충분)

2️⃣ 가장 중요한 3가지

 
 
php
// 1. 절대 경로 사용
define('ROOT_PATH', dirname(__DIR__));
require_once ROOT_PATH . '/config/config.php';

// 2. 초기화 파일 하나로 모든 것 로드
require_once 'init.php';  // 이것만 하면 끝!

// 3. 오토로더 사용 (클래스는 자동 로드)
spl_autoload_register(function($class) {
    require_once "classes/$class.php";
});
```

### 3️⃣ **권장 프로젝트 구조**
```
project/
├── init.php          ← 모든 페이지에서 이것만 include
├── config/           ← 설정
├── includes/         ← 공통 함수
├── classes/          ← 클래스들 (오토로드)
├── templates/        ← header, footer 등
└── pages/            ← 실제 페이지들

4️⃣ 실전 예제

 
 
php
 
// 모든 페이지의 시작
require_once 'init.php';  // 이것만으로 모든 설정 완료!

$pageTitle = '제목';
include TEMPLATES_PATH . '/header.php';

// 페이지 내용

include TEMPLATES_PATH . '/footer.php';

 

 

아래 코드를 예제로 참고하고 습득하여, 여러분의 코드에 적용을 검토해보세요 ^^

 

<?php
/**
 * PHP Include/Require 재사용 모범 사례
 * 
 * include vs require vs include_once vs require_once 차이점:
 * - include: 파일 없으면 Warning, 스크립트 계속 실행
 * - require: 파일 없으면 Fatal Error, 스크립트 중단
 * - include_once: 한 번만 포함 (중복 방지)
 * - require_once: 한 번만 포함 + Fatal Error
 */

// ============================================
// 1. 기본 디렉토리 구조
// ============================================
/*
project/
├── config/
│   ├── config.php          (설정)
│   └── constants.php       (상수)
├── includes/
│   ├── functions.php       (공통 함수)
│   └── helpers.php         (헬퍼 함수)
├── classes/
│   ├── Database.php        (DB 클래스)
│   └── User.php            (사용자 클래스)
├── templates/
│   ├── header.php          (헤더)
│   ├── footer.php          (푸터)
│   └── sidebar.php         (사이드바)
├── pages/
│   ├── index.php
│   └── about.php
└── init.php                (초기화 파일)
*/

// ============================================
// 2. 경로 설정 (config/constants.php)
// ============================================

// 절대 경로 정의 - 가장 중요!
define('ROOT_PATH', dirname(__DIR__)); // 프로젝트 루트
define('CONFIG_PATH', ROOT_PATH . '/config');
define('INCLUDES_PATH', ROOT_PATH . '/includes');
define('CLASSES_PATH', ROOT_PATH . '/classes');
define('TEMPLATES_PATH', ROOT_PATH . '/templates');

// URL 경로
define('BASE_URL', 'http://localhost/myproject');
define('ASSETS_URL', BASE_URL . '/assets');

// ============================================
// 3. 설정 파일 (config/config.php)
// ============================================

// 에러 리포팅 설정
error_reporting(E_ALL);
ini_set('display_errors', 1);

// 데이터베이스 설정
define('DB_HOST', 'localhost');
define('DB_NAME', 'mydb');
define('DB_USER', 'root');
define('DB_PASS', '');
define('DB_CHARSET', 'utf8mb4');

// 세션 시작
if (session_status() === PHP_SESSION_NONE) {
    session_start();
}

// 타임존 설정
date_default_timezone_set('Asia/Seoul');

// ============================================
// 4. 공통 함수 파일 (includes/functions.php)
// ============================================

/**
 * 안전한 HTML 출력
 */
function escape($string) {
    return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
}

/**
 * 리다이렉트
 */
function redirect($url) {
    header("Location: $url");
    exit;
}

/**
 * 현재 페이지 확인
 */
function isCurrentPage($page) {
    return basename($_SERVER['PHP_SELF']) === $page;
}

/**
 * 플래시 메시지 설정
 */
function setFlashMessage($type, $message) {
    $_SESSION['flash'] = [
        'type' => $type,
        'message' => $message
    ];
}

/**
 * 플래시 메시지 가져오기
 */
function getFlashMessage() {
    if (isset($_SESSION['flash'])) {
        $flash = $_SESSION['flash'];
        unset($_SESSION['flash']);
        return $flash;
    }
    return null;
}

/**
 * 디버그 출력
 */
function debug($data, $die = false) {
    echo '<pre>';
    print_r($data);
    echo '</pre>';
    if ($die) die();
}

// ============================================
// 5. 데이터베이스 클래스 (classes/Database.php)
// ============================================

class Database {
    private static $instance = null;
    private $pdo;
    
    private function __construct() {
        try {
            $dsn = "mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=" . DB_CHARSET;
            $options = [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                PDO::ATTR_EMULATE_PREPARES => false,
            ];
            
            $this->pdo = new PDO($dsn, DB_USER, DB_PASS, $options);
        } catch (PDOException $e) {
            die("데이터베이스 연결 실패: " . $e->getMessage());
        }
    }
    
    public static function getInstance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    public function getConnection() {
        return $this->pdo;
    }
    
    // 복제 방지
    private function __clone() {}
    
    // 역직렬화 방지
    public function __wakeup() {
        throw new Exception("Cannot unserialize singleton");
    }
}

// ============================================
// 6. 초기화 파일 (init.php)
// ============================================
// 이 파일을 모든 페이지에서 include하면 필요한 모든 것이 로드됨

// 상수 로드
require_once __DIR__ . '/config/constants.php';

// 설정 로드
require_once CONFIG_PATH . '/config.php';

// 공통 함수 로드
require_once INCLUDES_PATH . '/functions.php';

// 클래스 오토로더 (PSR-4 스타일)
spl_autoload_register(function ($className) {
    $file = CLASSES_PATH . '/' . $className . '.php';
    if (file_exists($file)) {
        require_once $file;
    }
});

// ============================================
// 7. 템플릿 파일들
// ============================================

// templates/header.php
?>
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?php echo $pageTitle ?? '기본 제목'; ?></title>
    <link rel="stylesheet" href="<?php echo ASSETS_URL; ?>/css/style.css">
</head>
<body>
    <header>
        <nav>
            <ul>
                <li><a href="index.php" <?php echo isCurrentPage('index.php') ? 'class="active"' : ''; ?>>홈</a></li>
                <li><a href="about.php" <?php echo isCurrentPage('about.php') ? 'class="active"' : ''; ?>>소개</a></li>
                <li><a href="contact.php" <?php echo isCurrentPage('contact.php') ? 'class="active"' : ''; ?>>연락처</a></li>
            </ul>
        </nav>
    </header>
    
    <?php 
    // 플래시 메시지 표시
    $flash = getFlashMessage();
    if ($flash): 
    ?>
        <div class="alert alert-<?php echo $flash['type']; ?>">
            <?php echo escape($flash['message']); ?>
        </div>
    <?php endif; ?>
    
    <main>

<?php
// templates/footer.php
?>
    </main>
    
    <footer>
        <p>&copy; <?php echo date('Y'); ?> 회사명. All rights reserved.</p>
    </footer>
    
    <script src="<?php echo ASSETS_URL; ?>/js/script.js"></script>
</body>
</html>

<?php
// templates/sidebar.php
?>
<aside class="sidebar">
    <h3>사이드바</h3>
    <ul>
        <li><a href="#">메뉴 1</a></li>
        <li><a href="#">메뉴 2</a></li>
        <li><a href="#">메뉴 3</a></li>
    </ul>
</aside>

<?php
// ============================================
// 8. 실제 페이지에서 사용 (pages/index.php)
// ============================================

// 초기화 파일 로드 - 단 하나만 필요!
require_once __DIR__ . '/../init.php';

// 페이지별 변수 설정
$pageTitle = '홈페이지';

// 데이터베이스 사용 예제
$db = Database::getInstance()->getConnection();
$stmt = $db->query("SELECT * FROM users LIMIT 5");
$users = $stmt->fetchAll();

// 헤더 포함
include TEMPLATES_PATH . '/header.php';
?>

<div class="container">
    <h1>환영합니다!</h1>
    
    <div class="content">
        <h2>사용자 목록</h2>
        <ul>
            <?php foreach ($users as $user): ?>
                <li><?php echo escape($user['name']); ?></li>
            <?php endforeach; ?>
        </ul>
    </div>
    
    <?php include TEMPLATES_PATH . '/sidebar.php'; ?>
</div>

<?php
// 푸터 포함
include TEMPLATES_PATH . '/footer.php';

// ============================================
// 9. 조건부 Include 예제
// ============================================

// 로그인 체크 후 다른 파일 포함
if (isset($_SESSION['user_id'])) {
    require_once INCLUDES_PATH . '/user_functions.php';
} else {
    require_once INCLUDES_PATH . '/guest_functions.php';
}

// 환경별 설정 파일
if (getenv('APP_ENV') === 'production') {
    require_once CONFIG_PATH . '/config.production.php';
} else {
    require_once CONFIG_PATH . '/config.development.php';
}

// ============================================
// 10. 모범 사례 요약
// ============================================

/**
 * DO (해야 할 것):
 * 
 * 1. require_once 사용: 설정, 클래스, 중요한 파일
 *    require_once 'init.php';
 * 
 * 2. include 사용: 템플릿, 선택적 파일
 *    include 'header.php';
 * 
 * 3. 절대 경로 사용
 *    require_once ROOT_PATH . '/config/config.php';
 * 
 * 4. 상수로 경로 정의
 *    define('INCLUDES_PATH', __DIR__ . '/includes');
 * 
 * 5. 초기화 파일 사용
 *    require_once 'init.php'; // 모든 것을 로드
 * 
 * 6. 오토로더 사용 (클래스)
 *    spl_autoload_register(function($class) { ... });
 * 
 * 7. 파일 존재 확인
 *    if (file_exists($file)) require_once $file;
 */

/**
 * DON'T (하지 말아야 할 것):
 * 
 * 1. 상대 경로 남용 (X)
 *    require '../../../config.php'; // 경로 헷갈림
 * 
 * 2. 같은 파일 여러 번 포함 (X)
 *    require 'config.php';  // require_once 사용!
 *    require 'config.php';  // 중복!
 * 
 * 3. include_path에 의존 (X)
 *    require 'config.php';  // 어디있는 파일인지 불명확
 * 
 * 4. 순환 참조 (X)
 *    // a.php: require 'b.php';
 *    // b.php: require 'a.php'; // 무한 루프!
 * 
 * 5. 로직과 템플릿 혼재 (X)
 *    // header.php에서 DB 쿼리 실행 등
 */

// ============================================
// 11. 고급 패턴: 중앙 라우터
// ============================================

// router.php
class Router {
    private $routes = [];
    
    public function add($route, $file) {
        $this->routes[$route] = $file;
    }
    
    public function dispatch($uri) {
        // 초기화
        require_once 'init.php';
        
        // 라우트 매칭
        if (isset($this->routes[$uri])) {
            $file = $this->routes[$uri];
            if (file_exists($file)) {
                require $file;
                return;
            }
        }
        
        // 404 페이지
        http_response_code(404);
        require '404.php';
    }
}

// index.php (프론트 컨트롤러)
$router = new Router();
$router->add('/', 'pages/home.php');
$router->add('/about', 'pages/about.php');
$router->add('/contact', 'pages/contact.php');

$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$router->dispatch($uri);

// ============================================
// 12. Composer 오토로더 (권장)
// ============================================

/**
 * composer.json 설정:
 * {
 *   "autoload": {
 *     "psr-4": {
 *       "App\\": "src/"
 *     },
 *     "files": [
 *       "includes/functions.php"
 *     ]
 *   }
 * }
 * 
 * 사용:
 * require_once 'vendor/autoload.php';
 * 
 * 이후 클래스는 자동으로 로드됨!
 * $user = new App\Models\User();
 */

// ============================================
// 13. 변수 스코프 주의
// ============================================

// config.php
$dbHost = 'localhost';  // 전역 변수

// functions.php
function connect() {
    global $dbHost;  // global 키워드 필요
    // 또는 $GLOBALS['dbHost']
    return new PDO("mysql:host=$dbHost");
}

// 더 나은 방법: 상수나 클래스 사용
define('DB_HOST', 'localhost');
class Config {
    const DB_HOST = 'localhost';
}
?>
TAGS.

Comments