TIP게시판

제목 plugin으로 interface정의 해서 사용하기.
글쓴이 SADBLUE 작성시각 2009/09/13 15:34:02
댓글 : 0 추천 : 0 스크랩 : 0 조회수 : 13010   RSS
금욜날 일이 좀 있어서 늦어졌습니다.
팁이라 하기에도 모하고 소스코드로 올리기도 애매한 그런 글 입니다.

filecache를 기반으로 인터페이스를 플러그인에 지정해서 쓰는 방법을 올립니다.
버그라던가 고쳐야 할점을 말씀 해 주시면 정말 감사 하겠습니다.
그러나 비난 하시면 상처 받습니다.Orz..
참고로 이 글은 객체의 개념이 없으시다면 상당히 난해할것이라 생각이 듭니다.;

1. 왜 인터페이스를 만들어야 하는가 부터 집고 넘어갑니다.
   filecache를 기본으로 설명할테니 예제도 이를 기반으로 하겠습니다.
   그리고 cache format은 json으로 합니다.
   다른 format은 처리해줘야 할 부분들이 많아서 구찮거든요-_-

   사용하는 이유는
   1. 어떤 filecache라도 동일한 method와 사용법을 갖습니다.
   2. 따라서 사용하기가 쉬워집니다.
   3. filecache를 추가 하더라도 interface만 맞추면 loader를 이용해서 편하게 쓸 수 있습니다.

   기초Data를 file로 내리는 이유는 db컨넥션을 줄이는데 우선 목적을 둡니다.
   cache가 1개 라면 굳이 이런 번거로운 방법을 쓸 이유는 없겠지요.
   그런데 두 개 이상이라면 얘기는 달라집니다.

   이런경우에 객체지향이 빛을 발하게됩니다.
   기본적으로 filecache는 생성, 읽기, 초기화 의 특성을 지닙니다.
   (삭제는 빼겠습니다. 안쓰면 그만인것이 캐쉬 이므로..머 넣으셔도 상관 없습니다.-_-;)
   어떤 cache든간에 똑같은 동작을 하지만 내부적으로는 다른 처리과정을 거치게 됩니다.
   이럴때에 추상Class나 Interface를 사용해서 Class를 구현을 하게 되면
   Interface상에 정의된 함수를 호출 하는 경우에 실제 생성된 객체의 method가 호출 되게 됩니다.

   이제 코드를 봅시다.
   저는 Interface말고 추상Class를 씁니다.

abstract class Filecache
{
    protected $m_szFile = null;        // 파일 경로
    protected $m_oController = null;    // 컨트롤러 참조 변수
    protected $m_szBuffer = null;        // 파일 내용 버퍼
    protected $m_bExist = false;        // 파일 존재 유무

/*
    기본적으로 method의 인자를 넘기게 되면 이 값은 메모리상에서 copy가 일어납니다.
    그러나 &연산자를 붙여주면 메모리를 참조 하게 됩니다.
    php상에선 오히려 &연산자를 써서 참조 하는게 않좋다는 글을 봤지만...
    취향입니다.-_-
*/
    function Filecache($pFile, &$pController)
    {
        $this->m_szFile = $pFile;
       
        // controller를 참조 하는 이유는 아래에 나오는 init method의 방식 때문입니다.
        // 이는 구현 부분에서 다시 언급 합니다.
        $this->m_oController = $pController;

        $this->m_bExist = file_exists($this->m_szFile);
    }

    // json_decode를 이용해 data를 return합니다.
    function getJsonData()
    {
        if ($this->m_szBuffer != "" && $this->m_szBuffer != null)
            return json_decode($this->m_szBuffer, true);
        else return false;
    }

    // 혹시 몰라서 그냥 buffer채로 넘기는 함수도 있습니다.
    // 만약 json이 아니라 단순 txt라면 이 함수를 쓰면 되겠습니다.
    function getStringData()
    {
        return $this->m_szBuffer;
    }

    function cacheExist()
    {
        return $this->m_bExist;
    }

    /*
        이 3개의 추상 method가 Interface가 됩니다.
        이 Class를 상속받는 Class들은 반드시 구현을 해야 하는 부분입니다.
    */
    abstract function makeFile($pData);
    abstract function loadFile();
    abstract function initFile();
}


이 소스를 filecache_pi.php로 저장을 했습니다.
그러나 써먹으려면 이 Class를 구현한 놈이 있어야겠죠.?
CI구조상 이렇게 만든 class를 별개의 파일로 나누어서 확장을 하려면
require_once를 사용 하는 수 밖에 없습니다.
그래서 저는 이렇게 한 Interface를 만들고 이를 상속 받는 class들은 한 파일 안에
다 넣기로 했습니다.

자 구현을 해봅시다.
class Infofile extends Filecache
{
    function Infofile($pFile, &$pController)
    {
        parent::Filecache($pFile, $pController);

        // 파일이 있다면 load를 하고 없으면 init을 합니다.
        if (file_exists($this->m_szFile)) $this->loadFile();
        else $this->initFile();
    }

    function loadFile()        // cache 파일을 읽어옵니다.
    {
        if (!file_exists($this->m_szFile))
        {
            $this->m_szBuffer = null;
            return;
        }
       
        $fd = fopen($this->m_szFile, "r");
        if ($fd == FALSE) return false;

        $buffer = "";

        while(!feof($fd))
            $buffer .= fgets($fd);

        if (strlen($buffer) == 0) return false;

        $this->m_szBuffer = $buffer;

        fclose($fd);
    }

    function makeFile($pData)    // cache 파일을 새로 만듭니다.
    {
        if (!is_array($pData)) return false;

        $fd = fopen($this->m_szFile, "w+");
        if ($fd == FALSE) return false;

        $buffer = json_encode($pData);
        $r = fwrite($fd, $buffer);

        if ($r != strlen($buffer))
        {
            fclose($fd);
            unlink($this->m_szFile);
            return false;
        }

        fclose($fd);
        return true;
    }

    /*
        cache 파일을 초기화 합니다.
        여기서 controller를 참조하는 이유가 생깁니다.
        init Method에서 model을 load 해서 갱신될 Data를  받게 했기 때문입니다.
        init file에만 controller 참조를 인자로 넘겨서 하셔도 됩니다.
        init file에 직접 data를 넘겨주겠다 하시면 controller참조는 아예 존재하지 않아도 됩니다.
    */   
    function initFile()
    {
        $this->m_oController->load->model("_MODEL_NAME_");

        $this->makeFile($this->m_oController->_MODEL_NAME_->_DATA_METHOD_);
           
        $this->loadFile();
    }
}

정말 간단하지요.?

이제 중요한 loader입니다.
loader는 일반 library에 둡니다.
그 이유는 controller에서 load를 하게 되면 자동적으로 객체를 참조 할 수 있게 되기 때문입니다.-_-
만약 plugin 또는 helper로 선언만 하게 되면
쓸 때마다 변수를 선언하고 생성을 해줘야만 하니까요.
상위 class에서 한번 load하면 하위 객체에서도 다 쓸수 있고 말이죠.
일일이 핸들링 할 필요가 없어지니 편하죠.

class filecacheloader
{
    protected $m_oController = null;
    protected $m_oFile = array();

    function filecacheloader($pValue = null)
    {
        $this->m_oController = &get_instance();
       
        if ($pValue != null) $this->loadFile($pValue["type"]);
    }
   
    function loadFile($pIndex)
    {
        if (array_key_exists($pIndex, $this->m_oFile)) return;
       
        switch($pIndex)
        {
            case "SITEINFO" :
                $szFilePath = _MAKE_FILE_PATH_NAME;
                $this->m_oFile[$pIndex] = new Infofile($szFilePath, $this->m_oController);
                break;
        }
    }

    function getData($pIndex)
    {
        return $this->m_oFile[$pIndex]->getJsonData();
    }

    function cacheExist($pIndex)
    {
        return $this->m_oFile[$pIndex]->cacheExist();
    }

    function makeFile($pIndex, $pData)
    {
        $this->m_oFile[$pIndex]->makeFile($pData);
    }
   
    function initFile($pIndex)
    {
        $this->m_oFile[$pIndex]->initFile();
    }
}

loader는 참 간단하지요.
단순하게 예약된 cache type을 받아서 생성되어 있는지 확인하고
생성되어 있지 않다면 새로 생성 하기만 하면 되는겁니다.

실제 controller 상에서는.
$this->load->plugin("filecache");
이렇게 선언된 plugin을 한번 load 해주고 loader를 load합니다. (helper로 만들어도 동일합니다. helper로 로드 하면 되겠지요.)

$this->load->library("filecacheloader", array("type" =>"SITEINFO"));

if (!$this->filecacheloader->cacheExist("SITEINFO"))
{
    $this->load->model(_MODEL_NAME_);
    $data = $this->_MODEL_NAME_->_METHOD_
    $this->filecacheloader->makeFile("SITEINFO", $data);
    /*
    // 또는
    $this->filecacheloader->initFile("SITEINFO");
    $data = $this->filecacheloader->getData("SITEINFO");
    */
}
else
{
    $data = $this->filecacheloader->getData("SITEINFO");
}

이렇게 쓰기만 하면 cache부분은 따로 손을 더 댈 필요가 없겠지요.?
참 쉽지요.?

태그 abstrace class,interface,plugin
 다음글 1.7.2 버젼업그레이드 주요확인사항 (6)
 이전글 MySQL date/datetime 핸들링 (1)

댓글

없음