마법 메서드 (Magic Methods): __call(), __get(), __set(), __isset(), __unset()

이건 다들 아는 기능이다. 메서드 호출, 멤버 접근 등을 저 메서드를 통해서 속일 수 있다. 예를 들어 PHP에서는 원래 메서드 오버로딩이 안되는데, 이걸 이용하면 오버로딩을 흉내낼 수도 있다.

SPL

원래 확장으로 만들어져 PHP 5.2부터는 기본으로 포함하게 된 SPL은 엄청난 축복이다. 이름을 보면 짐작할 수 있듯, C++ STL의 반복자 개념에 영향을 받아 만든 라이브러리다(나도 STL을 좋아한다). 이것을 잘 이용하면 유사 배열 객체를 만들 수 있다.

Traversable

이 인터페이스를 구현하면 foreach문에 객체를 집어넣어서 배열처럼 돌릴 수 있다. Traversable은 유사 인터페이스고, 실제로는 Iterator 혹은 IteratorAggregate를 구현하면 된다. 전자는 반복자를 직접 구현하는 방식이고, 후자는 IteratorAggregate->getIterator() 메서드를 구현하여 반복자 객체를 위임하는 방식이다. 간단하게 배열처럼만 작동하는 객체를 의도한다면 후자가 좋고, 좀더 정교한 것을 원하면 직접 Iterator를 구현하는 것이 좋다.

Countable

이 인터페이스를 구현하면 count() 함수에 넣었을 때 배열처럼 원소 개수를 반환하게 할 수 있다.

ArrayAccess

정말 유용하다. 이거 모르는 사람이 매우 많은데, 첨자 연산자([])를 오버로드할 수 있다. 단순히 값을 반환하는 것 말고도 해당 키가 존재하는지 확인하는 것(isset($obj[$key])), 해당 키의 원소를 삭제하는 것(unset($obj[$key])), 원소를 덧붙이는 것($obj[] = $value), 해당 키의 원소 값을 수정하거나 추가하는 것($obj[$key] = $value)이 가능하다.

아, 중요한 것 하나. 배열과 달리 ArrayAccess를 구현한 객체는 키 값으로 스칼라 외에 배열이나 객체도 받을 수 있다.

가변 인자: func_get_args()

가변적인 갯수의 인자를 전달받을 때 사용한다. PHP는 함수 선언시에 명시한 시그너쳐에 맞지 않는 호출을 하면 오류를 내는데, 시그너쳐의 갯수보다 많은 인자를 받을 땐 오류를 내지 않는다. 이걸 이용하면 가변 인자를 받으면서 쉽게 오류 처리를 할 수 있다. 예를 들어 인자 갯수는 가변적이지만, 꼭 맨 처음의 인자 하나는 배열로 받아야 한다는 제약 사항이 있다면?

function get_array_and() {
    $args = func_get_args();
    if(!count($args) or !is_array($args[0]))
        throw new InvalidArgumentException('First parameter must be array');
    $array = $args[0];

위와 같이 할 수도 있지만, 아래처럼 하면 굳이 제약 사항을 검사하고 오류를 내는 코드를 직접 작성할 필요가 없다.

function get_array_and(array $array) {
    $args = func_get_args();

주의할 것이 있다. 이 함수의 호출은 항상 맨 첫 문장, 대입식을 제외한 가장 바깥 표현식이어야 한다. 그렇지 않으면 의도한대로 작동하지 않는다. 이유는 나도 모른다. 하지만 이 버그는 PHP쪽에서는 유명하다.

eval()

전달된 PHP 코드 문자열을 해당 문맥에서 실행한다. eval('echo 1234;')1234를 출력한다. 그렇지만 표현식을 받지는 않는다.

$expr = '123 + 456';
$value = eval($expr);

위와 같이 하면 문장이 세미콜론(;)으로 종결되지 않았다며 구문 오류가 난다. 표현식을 평가하고 싶다면 아래와 같이 써야 한다.

eval("\$value = ($expr);");

Reflection

PHP 5에서 추가된 리플렉션 기능을 사용하면 클래스의 멤버와 메서드 목록을 얻는다던가, 함수의 시그너쳐를 추적하는 등의 일을 할 수 있다. 인자에 타입 힌트가 있는지, 있다면 어떤 타입인지, 기본값이 있는지, 변수 이름이 무엇인지 등도 알 수 있다. 이런걸 이용하면 Python의 키워드 인자도 흉내낼 수 있을 것이다.

__toString()

이것도 마법 메서드의 하나인데, PHP 5에서 추가된 기능이다. 이 메서드를 정의한 객체는 echo문으로 출력할 때 __toString()이 반환한 문자열을 출력한다. Python의 __str__ 속성과 비슷한 용도이다. 그런데 이게 PHP 5.2 이후로는 substr() 같이 문자열을 받는 함수에 전달될 때 자동으로 해당 문자열로 캐스팅도 된다. 물론 명시적으로 (string) 캐스팅 연산자를 쓰는 것도 잘 된다.

trigger_error()

웬만하면 예외를 던지는 것이 좋지만, PHP 에러를 내야할 필요가 있을 때 이걸 사용한다.

debug_backtrace()

이 함수를 사용하면 호출 스택을 추적하는 것이 가능하다. eval()을 통하는 것과, include, require를 통한 것도 모두 추적할 수 있다. 대체 이 함수를 어디에 쓰겠느냐고 무심코 지나치면 안된다. 이 함수를 기억하고 있는 것만으로도, 종종 우연히 이 함수를 이용하여 좀더 우아한 DSEL을 달성할 때가 많다.

이 함수를 이용하는 대신 예외 객체를 생성하여 Exception->getTrace() 메서드로 받아내는 방법도 있다.

__FILE__ 상수

__FILE__ 상수의 값은 include, require 등과 무관하게 해당 상수는 현재 코드가 위치한 실제 파일 경로이다. 예를 들어 require_once dirname(__FILE__).'/file.php'과 같이 해당 소스 파일과 같은 위치에 있는 file.php를 불러올 수 있다. (저렇게 하지 않으면 include 호출의 맨 위쪽에 있는 파일에 상대한 경로로 인클루드를 시도한다.)

operator 확장

PHP에 기본적으로 포함되지는 않았지만, 매우 유용한 확장이다. 연산자 재정의를 가능하게 해준다. C++의 Boost.Spirit 라이브러리 같은 것을 보면 연산자 재정의가 얼마나 언어의 표현력을 높여주는지 알 수 있다. 자세한 것은 내가 예전에 정리해둔 문서를 참고하시라.

 

출처: http://blog.dahlia.pe.kr/?s=lexical


+ Recent posts