PHP & Others

php에서 싱글톤 패턴 이용하기

페이지 정보

본문

php를 클래스화 해서 사용하다보니 시시때때로 필요한 클래스들을 만들면서 기존에 만들었던것들을 응용해서 만들게 됩니다. 개별적으로 놓고 보면 괜찮지만.. 프로그램 규모가 커지면 같은 클래스를 여기저기서 인스턴스 해서 사용하게 되는 일이 발생하게 되는게 항상 찜찜하게 여겨졌는데.. 아는분의 도움으로 웹서핑중 싱글톤 패턴이란것을 알게되었습니다.

부분적으로는 프로그램에 적용도 하고 있었지만 그걸 뭐라고 부르는지도 모르고 있었거든요^^

싱글톤 패턴이란, 한번 인스턴스한 오브젝트를 다시 만들지 않고 재사용 하는 프로그래밍 방법론을 말하는데요.. 지난번 클래스로더 얘기가나왔을때 잠깐 보여드렸던 소스를 이렇게 수정하였습니다.

class WebApp {

        function import($module) {
                if (strpos($module,'.')) {
                        $_part = explode('.',$module);
                        $module = array_pop($_part);
                        $path = implode('/',$_part)."/";
                }
                $file = $path."class.$module.php";
                require_once($file);
                return true;
        }

        function singleton($name) {
                static $jar;
                if (!is_array($jar)) $jar = array();
                if (is_object($jar[$name])) {
                        return $jar[$name];
                } else {
                        WebApp::import($name);
                        $argv = func_get_args();
                        unset($argv[0]);
                        $params = array();
                        foreach ($argv as $param) {
                                $param = (is_numeric($param)) ? $param : "\\"$param\\"";
                                $params[] = $param;
                        }
                        $params = implode(',',$params);
                        eval("\\$o = new $name($params);");
                        $jar[$name] = $o;
                        return $jar[$name];
                }
        }
}



이것은 WebApp라는 제작시스템에서 쓰이는 메인 클래스의 일부인데요.. 우선 DB 클래스를 불러서 데이타베이스 기능을 쓰고싶다면 다음과같이 호출합니다.

$DB = &WebApp::singleton('DB');

기존에는 DB 클래스를 이용하는 다른 클래스를 만들때 다음과같이 코딩했었습니다.

class AutoQuery extends DB {

        function AutoQuery($tablename="") {
                $this->DB();
        }
}


이렇게 되면 AutoQuery 클래스는 DB 클래스의 기능을 상속하는 유용한 클래스가 될수는 있지만 DB 클래스와 AutoQuery 클래스가 함께 쓰이는 프로그램에선 DB 커넥션자체도 2번이 맺어지게 되며, 클래스의 인스턴스가 각각 2번 메모리에 올라와있어야 했습니다.
이걸 다음과같이 코딩하면 DB 클래스 인스턴스의 자원을 재사용하며 확장된 기능을 수행하는 클래스를 만들 수 있습니다.

class AutoQuery {
        var $sql;

        function AutoQuery($tablename="") {
                $this->sql = &WebApp::singleton('DB');
        }
}


이렇게 되면 AutoQuery 클래스의 $sql 맴버변수는 WebApp 클래스의 static 변수 $jar['DB'] 를 가리키게 되고, 이것은 위에서 이미 한번 인스탄스 되었으므로 메모리상에서 공유되게 됩니다. 물론 위에서 선언된적이 없다면 자연스럽게 로드되어 선언되며 사용에는 아무런 변화가 없게 됩니다.

관심 있으신분은 php 4.2.x 부터 자동으로 함께 깔리는 pear 의 소스를 한번 공부해보시기 바랍니다. 위치는 /usr/local/lib/php/pear 가 보통이며, 저 위치에 없다면 which pear 해보시면 어디 있는지 알수 있을껍니다.

ps. 제가 제대로 알지 못해서 잘못 적은 부분이나 보충할 부분 있으면 코멘트로 수정해주세요.
또 다른 효율적인 프로그램 방법이 있다면 소개시켜주시구요..

관련자료

nuno님의 댓글

  약간의 이해 부족이 있었습니다. 함수에 대한 레퍼런스를 돌려받으려면 함수 이름과 참조하려는 시점에서 두번 다 &를 써야 한다고 나와있네요

singleton() 메소드는 function &singleton() 으로 고쳐야 합니다.

<a href=http://kr.php.net/manual/kr/language.references.return.php target=_blank>http://kr.php.net/manual/kr/language.references.return.php</a> 10/08 9:48:51 
 
static 키워드는 4.x 부터 아무 의심없이 쓰고있었습니다..
<a href=http://kr.php.net/manual/kr/language.variables.scope.php target=_blank>http://kr.php.net/manual/kr/language.variables.scope.php</a>

nuno님의 댓글

  $sql = &WebApp::singleton('DB');
$board = new BOARD;
$member = new MEMBER;


이런식으로 해놓고

class BOARD {
function BOARD() {
$this->sql = &WebApp::singleton('DB');
}
}


class MEMBER {
function MEMBER() {
$this->sql = &WebApp::singleton('DB');
}
}

이런식으로 해도 공유되어 한번만 로드 됩니다.

nuno님의 댓글

  실제로 한번만 로드되었는지 확인해보려면
echo ($board->sql === $member->sql);
해보시면 되겠네요^^ 제가 싱글톤을 생각하게 된 이유가 딱 그런 상황때문이었습니다. 멤버,게시판 등등에서 계속 DB 클래스를 불러다 쓰니 커넥션리소스3개에 클래스 인스턴스 3개가 생기는게 불만이었단 말이죠
Today's proverb
진정한 여행은 새로운 풍경을 보는 것이 아니라, 새로운 시야를 갖는 것이다. (M.프루스트)