PHP: Class 데이터 모델 클래스 패턴 예시


PHP 기반 애플리케이션 개발 시 데이터베이스(DB) 레코드를 객체 지향적으로 다루기 위한 데이터 모델 클래스 패턴입니다. 싱글톤 패턴 응용 방식인 instance() 팩토리 메서드부터 PDO 기반 데이터 로딩(load), 목록 조회(retrieve) 메서드 구현 예제를 정리합니다.

📌 목차

  • 1. 인스턴스 캐싱 (멀티턴 싱글톤 패턴)
  • 2. 단일 데이터 로딩 (load)
  • 3. 목록 데이터 페이징 조회 (retrieve)
  • 4. 전체 클래스 구조 및 모범 사례

1. 인스턴스 캐싱 (멀티턴 싱글톤 패턴)

동일한 PK(Primary Key)를 가진 객체가 중복 생성되는 것을 방지하고 메모리를 절약하기 위해 정적 배열에 인스턴스를 캐싱하는 방식을 사용합니다.

// PK 기반 객체 인스턴스 재사용 (Multiton Pattern)
static public function instance($pk)
{
    static $sInstance = array();

    $pk = intval($pk);

    if (isset($sInstance[$pk]) === false) {
        $className      = __CLASS__;
        $obj            = new $className($pk);
        $sInstance[$pk] = $obj;
    }

    return $sInstance[$pk];
}

public function __construct($id = null)
{
    $this->id = $id;
}

2. 단일 데이터 로딩 (load)

생성자에서 전달받은 식별자($this->id)를 기준으로 PDO 바인딩 처리를 수행하여 DB 데이터를 불러온 뒤 멤버 변수에 매핑합니다.

/**
 * 데이터베이스에서 정보를 읽어와 멤버변수에 정의합니다.
 * @return $this
 */
public function load()
{
    if (!$this->id) {
        return $this;
    }

    $pdo = PDO_Manage::getConnectDB();
    $query = 'SELECT *
                ,(SELECT count(1) 
                  FROM ' . self::moodlesjc . 'm_cdms_lecture 
                  WHERE subjectid = t.id AND confirm = 2) as lectotal2 
              FROM ' . self::moodlesjc . 'm_cdms_subject t
              WHERE id = :id';
              
    $stmt = $pdo->prepare($query);
    $stmt->bindValue(':id', $this->id, PDO::PARAM_INT);
    $stmt->execute();

    $row = $stmt->fetch(PDO::FETCH_ASSOC);
    if ($row) {
        $this->loadByRowData($row);
    }

    return $this;
}

3. 목록 데이터 페이징 조회 (retrieve)

검색 조건 및 페이징 처리를 포함하여 조건에 부합하는 여러 레코드를 객체 배열(Array of Objects) 형태로 반환하는 정적 메서드입니다.

public static function retrieve($param = null)
{
    $pdo = PDO_Manage::getConnectDB();
    
    // MSSQL Window Function 기반 서브쿼리 작성
    $query = 'SELECT *
                FROM (
                         SELECT *,
                                ROW_NUMBER() OVER (ORDER BY id DESC) AS Seq
                         FROM ' . self::moodlesjc . 'm_cdms_subject
                         ' . self::_makeWhere($param) . '
                     ) t ';

    $where = self::_makeMssqlPaging($param);
    $stmt = $pdo->prepare($query . $where . self::_makeSort($param));

    self::_doBindValue($stmt, $param);
    $stmt->execute();
    
    $retrieveArr = array();
    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
        $cdmsSubject = new cdmsSubject();
        $cdmsSubject->loadByRowData($row);
        $retrieveArr[] = $cdmsSubject;
    }

    return $retrieveArr;
}

public function add()
{
    // C(Create) 등록 로직 구현
}

public function modify()
{
    // U(Update) 수정 로직 구현
}

4. 전체 클래스 구조 및 모범 사례

위와 같은 형태의 데이터 모델 클래스를 작성할 때는 다음 사안들을 고려하는 것이 바람직합니다.

  • 메모리 관리: instance() 메서드로 동일 PK 객체의 중복 조회를 방지하여 메모리 오버헤드를 낮출 수 있습니다.
  • 바인딩 처리: SQL Injection 방지를 위해 동적 파라미터는 항상 Prepared Statement의 bindValue()를 활용합니다.
  • 체이닝 지원: $this->load()와 같이 메서드가 $this를 반환하면 $obj->load()->getName()과 같은 체이닝 표현식이 가능합니다.