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
일의 쾌감은 고됨을 잊게 한다. (호라티우스)