PHP에서 런타임에 함수를 제거하는 방법
PHP에서 함수와 클래스는 항상 전역 범위(global scope)를 가집니다. 이는 함수 내부에서 정의된 함수라도 외부에서 호출할 수 있고, 그 반대의 경우에도 마찬가지라는 의미입니다.
하지만 PHP는 함수 오버로딩(function overloading)을 지원하지 않기 때문에, 한 번 선언된 함수를 같은 이름으로 다시 정의하거나 덮어쓰는 것은 불가능합니다.
이러한 제약을 우회하는 대표적인 방법은 함수를 익명 함수(anonymous function)로 정의한 뒤, 작업이 끝나면 unset()으로 변수를 해제하여 사실상 '제거'하는 것입니다.
예제 코드
if (function_exists('get_magic_quotes_gpc') && @get_magic_quotes_gpc()) {
$my_fn = create_function('&$v, $k', '$v = stripslashes($v);');
array_walk_recursive(array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST), $my_fn);
unset($my_fn);
}
주의할 점
익명 함수는 자기 자신 내부에서 재귀 호출(recursion)이 불가능합니다. 따라서 위 예제처럼 중첩된 배열을 순회해야 하는 상황에서는 array_walk_recursive()를 활용하는 것이 좋은 우회 방법이 됩니다.
최신 PHP 버전에서의 변화
참고로 위 코드에 사용된 create_function()은 PHP 7.2부터 폐기(deprecated)되었으며, PHP 8.0부터는 완전히 제거되었습니다. 최신 버전에서는 아래와 같이 익명 함수(Closure) 문법을 직접 사용하는 것이 표준적이고 안전합니다.
if (function_exists('get_magic_quotes_gpc') && @get_magic_quotes_gpc()) {
$my_fn = function (&$v, $k) {
$v = stripslashes($v);
};
array_walk_recursive([&$_GET, &$_POST, &$_COOKIE, &$_REQUEST], $my_fn);
unset($my_fn); // 사용 후 함수 참조 제거
}
이름 있는 함수를 실제로 제거해야 한다면?
일반적으로 PHP 코어 차원에서는 이미 선언된 이름 있는(named) 함수를 런타임에 삭제하는 공식 API를 제공하지 않습니다. 만약 이런 기능이 반드시 필요하다면 runkit(runkit7) 확장 모듈의 runkit7_function_remove() 같은 함수를 사용할 수 있으나, 프로덕션 환경에서는 신중하게 검토한 후 사용하는 것이 좋습니다.