1. 실제 적용 흐름 전체 조감
이 챕터는 index.php와 Dispatcher.php의 실제 소스를 기반으로 Extend가 어떤 순서로, 어떤 상태에서 실행되는지를 단계별로 상세히 설명합니다.
1.1 index.php 전체 실행 순서 (STEP 1~7)
STEP 1 — 클래스•함수 정의 파일 로드
functions.php, DxCache, Secure, Database, HookManager, PluginRegistry, Auth, DxPoint, DxSite, DxTheme, DxExtend, Router, Dispatcher 순서로 require_once. 이 단계에서는 실행이 없고 정의만 합니다.
STEP 2 — 보안 초기화
Secure::getInstance(). 세션 설정 → (조건부) 세션 시작 → 보안 헤더 발행 → CSRF 토큰 선제 발급.
STEP 3 — DB 연결 + 설정 로드
data/config.php require. 이 안에서 Database::getInstance()->connect() 실행. DX_DEBUG, DX_SECRET_KEY 등 상수 확정.
STEP 4 — CMS 객체 초기화
HookManager → PluginRegistry → load_plugins() → DxSite → DxTheme → Auth → DxContainer.모든 플러그인의 dx_add_hook() 등록이 이 단계에서 완료됩니다.
DxExtend::ensureDirs()로 extend/ 폴더 자동 생성.
extend/top/ 실행 ← STEP 4 완료 직후
DxExtend::getInstance()->runTop(["version"=>DX_VERSION, "path"=>dx_request_uri()]).모든 초기화가 완료된 상태이므로 Database, Auth, DxSite, DxCache, HookManager 전부 사용 가능.
라우트 정보($GLOBALS["dx_route"])는 아직 미설정.
STEP 5 — 라우팅 + 디스패치
routes/ 폴더 자동 로드 → DxRouter::dispatch() 시도 → 미매칭 시 Dispatcher 폴백. Dispatcher::dispatch() 내부: ① Router::resolve()로 라우트 확정 → $GLOBALS["dx_route"] 설정 🟡 extend/middle/ 실행
② switch($type) → 핸들러 실행 + 렌더링
extend/bottom/ 실행 ← 렌더링 완료 후
DxExtend::getInstance()->runBottom(["elapsed"=>경과ms]).HTML이 ob 버퍼에 완성된 상태. 헤더 변경 불가. ob_end_flush() 직전.
🔍 핵심 타임라인 요약
① top 실행 시점: Auth•DB•플러그인 전부 준비 완료. 라우트 정보 없음. 헤더•리다이렉트 가능.
② middle 실행 시점: $GLOBALS["dx_route"]["type"] 확정. 어떤 페이지인지 알고 처리 가능.
③ bottom 실행 시점: HTML 버퍼 완성. echo로 HTML 말단에 추가 가능. 헤더 변경 불가.
1.2 $GLOBALS["dx_route"] 구조 상세
middle/bottom 파일에서 사용할 수 있는 $GLOBALS["dx_route"] (또는 inject된 $route ) 배열의 실제 구조입니다. Router::resolve()가 URL을 분석하여 확정합니다.
📄 dx_route 배열 구조
// $GLOBALS["dx_route"] 전체 구조 (Dispatcher::dispatch() 직후)
// ── 공통 키 (모든 라우트 타입) ──────────────────────────
$route["type"] // "home" | "page" | "board" | "admin" | "auth" | "api" | "search" | "404"
$route["slug"] // 페이지 슬러그 ("about", "home", "free" 등)
// ── board 타입 전용 ────────────────────────────────────
$route["board_key"] // 게시판 키 (예: "free", "notice", "gallery")
$route["board"] // 게시판 전체 설정 배열 (DB에서 로드된 행)
$route["action"] // "list" | "view" | "write" | "edit" | "delete"
$route["id"] // 글 ID (view/edit/delete 시)
// ── page 타입 전용 ────────────────────────────────────
$route["page"] // 페이지 전체 설정 배열
// ── admin 타입 전용 ───────────────────────────────────
$route["admin_action"] // 관리자 액션 문자열
// middle context에서 inject된 변수 (extract()로 주입)
$type // $route["type"]과 동일
$route // 위 배열 전체
// 사용 예시:
if ($type === "board" && isset($route["board_key"])) {
$boardKey = $route["board_key"]; // "free", "notice" 등
}
1.3 context 변수 inject 상세
DxExtend::safeExec() 는 extract($context, EXTR_SKIP) 를 호출하여 컨텍스트 배열의 키를 파일 로컬 변수로 자동 주입합니다. 슬롯별로 주입되는 변수가 다릅니다.| 슬롯 | 주입되는 변수 | 타입 | 설명 |
|---|---|---|---|
| top | $version | string | DX_VERSION ("8.1.0") |
| top | $path | string | dx_request_uri() — 현재 요청 경로 |
| top | $dx_extend_slot | string | "top" — 항상 주입 |
| middle | $type | string | 라우트 타입 (board/page/home/…) |
| middle | $route | array | 전체 라우트 배열 (위 1.2 참조) |
| middle | $dx_extend_slot | string | "middle" — 항상 주입 |
| bottom | $elapsed | float | 경과 시간(ms) — microtime 기반 |
| bottom | $dx_extend_slot | string | "bottom" — 항상 주입 |
💡 EXTR_SKIP 안전 모드
extract($context, EXTR_SKIP)은 파일 내에 이미 같은 이름의 변수가 있으면 덮어쓰지 않습니다.
예: extend 파일 첫 줄에 $type = "custom"; 을 정의하면 context의 $type이 주입되지 않습니다.
반대로, context에 없는 변수는 주입되지 않으므로 isset() 확인이 필요합니다.
1.4 파일 수집 알고리즘과 실행 순서 결정
DxExtend::collectFiles($dir) 가 실제로 파일을 수집하는 방식과, 그 결과 실행 순서가 어떻게 결정되는지 구체적인 예시로 설명합니다.
📄 파일 수집 알고리즘 예시
// DxExtend::collectFiles() 단계별 동작
// ① 슬롯 폴더 직접 *.php 수집
$found = glob("extend/top/*.php");
// 결과: ["extend/top/01_darkmode_early.php", "extend/top/02_maintenance.php", ...]
// .disabled 파일은 *.php 패턴에 불일치 → 자동 제외
sort($found); // 파일명 오름차순 정렬 (문자열 비교)
// ② 하위 폴더 1단계 재귀
$subDirs = glob("extend/top/*", GLOB_ONLYDIR);
sort($subDirs); // 폴더명도 오름차순
// 예시 디렉터리:
// extend/top/
// 01_darkmode_early.php ← 직접 파일
// 05_maintenance.php ← 직접 파일
// security/ ← 하위 폴더
// 01_ip_block.php
// 02_rate_limit.php
// utils/ ← 하위 폴더
// 01_globals.php
// 최종 실행 순서:
// 1. extend/top/01_darkmode_early.php
// 2. extend/top/05_maintenance.php
// 3. extend/top/security/01_ip_block.php
// 4. extend/top/security/02_rate_limit.php
// 5. extend/top/utils/01_globals.php
Extend 실제 소스 코드 완전 분석 • 12가지 실전 사례