PHP & Others

PHP 클래스 캡슐화하기

페이지 정보

본문


class test
{
        var $elem;
        var $public_var = array('pub1','pub2','pub3');
        var $public_method = array('method1');

        function __get($key, &$val)
        {
                if (!in_array($key, $this->public_var)) {
                        // false를 반환해도 에러처리를 하지 않습니다.
                        // 에러처리를 하려면 이 부분에 입력하세요.
                        echo '`$'.$key.'` is not public property!';
                        return false;
                } elseif (isset($this->elem[$key])) {
                        echo 2;
                        $val = $this->elem[$key];
                        return true;
                } else {
                        echo 3;
                        return false;
                }
        }

        function __set($key, $val) {
                if (in_array($key, $this->public_var)) {
                        $this->elem[$key] = $val;
                        return true;
                } else {
                        // 프로퍼티 셋은 false를 반환하면 에러처리를 합니다.
                        // 별도의 에러처리를 하고 싶으시면 이 부분에 입력하세요.
                        echo '`$'.$key.'` is Not public property!';
                        return false;
                }
        }

        // FIXME : __call 에 대한 오버로드가 제대로 작동하지 않습니다.
        // 잘 되다가 갑자기 안되는데, 이유는 모르겠습니다. ^^;;
        function __call($method, $args, &$return)
        {
                if ($method == get_class(&$this)) {
                        return true;
                } elseif (in_array($method, $this->public_method)) {
                        $return = call_user_method_array ( $method, &$this, $args);
                        return true;
                } else {
                        // 퍼블릭 함수가 아닐때
                        return true;
                }
        }

        function method1($str1, $str2) //public
        {
                echo 'method1->params = '.$str1.' glue '.$str2.'';
        }

        function method2($str1, $str2) //private
        {
                echo 'method2->params = '.$str1.' glue '.$str2.'';
        }
}

overload('test');

$test = new test;

$test->pub1 = '111';
$test->method2('1', '2');
$test->method1('3', '4');


모양을 보면 대강 이해하실겁니다.
PHP의 클래스가 불완전한 이유중에 하나가 오버로드와 오버라이딩이 지원안된다는 거였는데(저는 그렇게 알고 있었습니다), 거기에 또 하나의 이유가 있다면 캡슐화가 안된다는 거죠. 클래스의 큰 특징중의 하나가 없으니 사실 PHP의 클래스는 클래스라기 보다는 함수모음이었죠.

오늘 우연히 overload 라는 함수를 보고 그 예제를 보게 되었는데, 정말 유용하게 쓸 수 있을 것 같아서 소개하려고 하다가 그 김에 캡슐화를 구현해보았습니다.

클래스 선언부에 var 로 선언한 프로퍼티들은 사실 외부에서 값을 변경해도 아무런 저항없이(?) 변경되어야 했지만, 클래스 내장메소드인 __get 과 __set 을 오버로드하면 충분히 캡슐화할 수 있습니다. 미리 공개 프로퍼티를 배열로 정해주고, 클래스 외부에서 요구하는 프로퍼티의 이름이 공개 프로퍼티가 아니면 에러처리를 하는 것입니다.
설명잘하는 능력이 없어서 길게 설명드리지는 못하지만, 예문도 함께 올렸으니 한번씩 테스트해보시면 재미있는 결과를 얻을 수 있을겁니다.

※ PHP 버전이 4.2.0 보다 높아야 하며, __call 메소드는 4.3.0 이후 가능. 4.3.0 이전에는 따로 옵션을 줘서(--enable-overload) 컴파일해야 사용가능하나, 4.3.0부터는 따로 옵션을 주지 않아도 포함되어 컴파일 된다.


P.S// 원래는 __call 도 오버로드하여 method 도 public과 private 를 구현하려 했는데, 주석에 쓴대로 이상하게 안 먹히더군요. ㅡ.ㅡ;; 그것도 잘 되다가 갑자기 __call 자체를 안 불러버리는 요상한 일이 발생하더군요. 쩝....

 

관련자료

등록된 댓글이 없습니다.
Today's proverb
참된 행복은 눈에 보이지 않는다. 참된 행복은 작지만 자기 일에 만족하고 자기 안에서 그것을 찾는 사람에게만 보이도록 가만 가만히 찾아온다.