by 존 코그셸(John Coggeshall), 역 한빛 리포터 1기 이호재
이번 기사에서는 미확정 매개 변수(variable-length argument list)라고 하는 고급 함수 개념에 대해서 토론해 보고자 한다. 그리고 PHP에서 동적 함수와 변수 이름을 어떻게 사용하는지 설명할 것이다.
미확정 매개 변수(Variable-length argument lists)
이 글에서는 매개 변수를 정의해 주지 않아도, 전달되는 매개 변수의 개수에 상관없이 잘 작동하는 함수를 만드는 법에 대해 얘기할 것이다. 이러한 미확정 매개 변수 개념은 func_num_args(), func_get_arg(), func_get_args()와 같이 작은 수의 PHP 내장 함수를 사용해서 만든다.
func_로 시작하는 함수 집합
func_로 시작하는 함수는 다른 함수 내에서 작동하는 함수 집합이다. 이 func_* 함수는 함수로 전달된 매개 변수의 정보를 받는다. PHP에서는 매개 변수가 정의되어 있지 않은 함수로 매개 변수를 전달할 수 있기 때문에, 이러한 func_* 함수로 매개 변수 개수에 제한이 없는 함수를 만들 수 있다. 그 예제는 다음과 같다.
<?php
function dynamic_args() {
for($i = 0 ; $i < func_num_args(); $i++) {
echo "Argument $i = ".func_get_arg($i)."<br />";
}
}
dynamic_args("a", "b", "c", "d", "e");
?>
|
기존의 함수와 비교해 보면, 이 예제는 틀린 것 같다. 매개 변수가 없는 함수를 정의했는데, 이 함수를 호출할 때 5개의 매개 변수를 전달하기 때문이다. 이미 언급했듯이, PHP에서는 에러 없이 함수에 여분의 매개 변수를 전달하므로, 함수 자체에 관심을 가져야 한다.
위의 함수에서 func_* 계열 함수 두 개를 사용하여, dynamic_args()에 전달된 매개 변수의 정보를 얻었다. 첫째로, func_num_args()로 dynamic_args()에 전달된 전체 매개 변수의 수를 알아냈다. 이 경우에 전달된 매개 변수의 수는 5이다. 그리고 나서 for 반복문에서 func_get_args() 함수를 사용하였고, 이 함수에 $i라는 색인을 넘겨주었다. 이 함수가 실행된 후 func_get_args() 함수는 전달된 색인의 매개 변수값을 리턴해준다. 이러한 작업은 for 반복문이 끝날 때까지 계속된다. 위와 같이 매개 변수가 있는 dynamic_args() 함수를 부른 결과는 브라우저에서 다음과 같다.
Argument 0 = a
Argument 1 = b
Argument 2 = c
Argument 3 = d
Argument 4 = e
|
여러분도 알다시피, 이처럼 강력한 함수를 사용해서 무수한 매개 변수를 받을 수 있는 함수를 쉽게 만들 수 있다. 다음과 같이 하나의 고정된 매개 변수와 무수한 매개 변수를 받는 함수를 만들 수도 있다.
<?php
function implode_str($glue) {
$string = "";
for($i = 1; $i < func_num_args(); $i++) {
$string .= $glue;
$string .= func_get_arg($i);
}
return $string;
}
echo implode_str("-", "This", "is" "a" "test");
?>
|
위의 예제에서는 implode_str() 함수에 단일 매개 변수인 $glue이 반드시 필요하도록 정의하였다. 그리고 나서 함수에서 전달된 여분의 매개 변수와 $glue 변수의 값에 기초하여 앞의 예제와 동일한 함수로 $string 문자열을 만들었다. for 반복문이 0부터 시작하지 않고 1부터 시작했다는 것에 주목하자. 이는 선언문에서 하나의 변수를 매개 변수로 받기 때문에 첫째 매개 변수를 무시하기 위해서이다. 위와 같은 매개 변수로 함수를 실행한다면 그 결과는 "This-is-a-test"와 같다. 이는 미확정 매개 변수를 생성하기 위해 함수 선언과 func_* 함수를 섞어 결합시킨 많은 방법 중의 하나일 뿐이다.
가변 변수와 함수 이름
주 : 가변 변수와 함수가 부적절하게 사용되면 보안상 잠재적 위험이 있다. 가변 변수와 함수를 사용하기 전에 사용자가 악의를 가지고 입력해서 발생할 수 있는 보안상 취약점을 고려해야 한다.
PHP는 동적인 매개 변수를 넘어서서, 변수를 동적으로 사용할 수 있는 기능뿐만 아니라 함수를 동적으로 부를 수 있는 기능도 지원한다. 다시 말해 스크립트가 실행되기 전까지 함수와 변수의 이름을 몰라도, 그 함수를 호출하고 변수에 접근할 수 있는 스크립트를 작성할 수 있는 것이다.
가변 변수
PHP에서는 스크립트가 실행되기 전까지 이름을 몰라도 특정 변수에 접근할 수 있다. ${변수 이름} 과 같이 정의되는 특별한 변수 문법을 사용하면 된다. 이때 변수 이름은 "foo" 와 같은 상수, 또는 이름을 나타내는 문자열을 포함한 또 다른 변수를 의미한다. 다소 혼란스럽다면, 다음 예제를 보자.
<?php
$foo = "This is the variable foo<br />";
$bar = "This is the variable bar<br />";
$foobar = "This is the variable foobar<br />";
$foo_name = "foo";
$bar_name = "bar";
echo $foo;
echo $bar;
echo ${$foo_name};
echo ${$bar_name};
echo ${$foo_name.$bar_name};
?>
|
위의 예제는 다른 변수를 브라우저에 출력해 놓은 단순한 스크립트이다. 이해하기 쉬워 보이지만 마지막 세 개의 echo 문은 매우 이상한 변수를 참조한다. echo ${$foo_name};문을 살펴보자. 이 행에서는 echo에 $foo_name의 값을 변수명으로 갖는 변수를 출력하도록 한다. $foo_name의 값이 "foo"이기 때문에 echo문은 변수 $foo가 가지고 있는 값을 브라우저에 출력할 것이다. 그 다음 문장은 이와 비슷하지만, 마지막 문장은 약간 다르다. 여기에서는 문자열 결합 연산자인 "."$foo_name과 $bar_name의 값을 합쳤다. 이는 마지막 echo문에서 변수 이름으로 사용될 "foobar" 문자열을 만들기 위해서이다. 이 예제의 결과는 다음과 같다.
This is the variable foo
This is the variable bar
This is the variable foo
This is the variable bar
This is the variable foobar
|
이 문법을 사용하면, 더 적은 노력으로 동적이며 복잡한 스크립트를 작성할 수 있다. 지금까지 가변 변수를 사용하는 법을 알아보았다. 이제 변수값에 기초한 함수를 호출하는 방법을 살펴보도록 하자.
가변 함수
가변 함수는 가변 변수와 같은 원리로 동작한다. 기본적으로 PHP에서 함수를 나타내는 문자열을 포함한 변수가 있다면, 변수에 괄호와 매개 변수를 붙여서 그 함수를 부를 수 있다.
<?php
function myfunc($msg) {
echo $msg."<br />";
}
$func_name = "myfunc";
$func_name("Hello, this is a test");
?>
|
위 예제는 myfunc() 함수를 호출하고 "Hello, this is a test" 메시지를 매개 변수로 전달한다. 함수 myfunc의 이름을 갖고 있는 $func_name 변수를 사용해서 함수를 호출한다.
동적 함수 생성
함수를 동적으로 호출하는 것을 넘어서, 함수를 동적으로 생성하는 것도 가능하다. PHP의 create_function() 함수를 사용하면 된다. 이 함수의 문법은 다음과 같다.
string create_function(string args, string code);
|
이 함수를 호출할 때 두 개의 매개 변수를 전달하게 된다. 첫째 매개 변수인 args는 함수 선언문에서 괄호 사이에 들어가는 매개 변수를 포함하는 문자열이다. 둘째 매개 변수인 code는 주어진 함수의 몸체를 구성하는 실질적인 PHP 코드를 포함하는 문자열이다. create_function()을 호출할 때, 명시된 함수가 생성되고 생성된 함수 이름이 포함된 변수가 리턴된다. 나중에는 이 이름으로 함수를 호출하면 된다. 다음 예제를 살펴보자.
<?php
// Normal function definition
function my_normal_func($foo, $bar) {
echo "Hi, PHP!";
}
// Dynamic function definition
$func_name = create_function("$foo, $bar",
"echo "Hi, PHP!";" );
?>
|
위의 예제에서, 우리는 결과물이 동일한 두 함수를 만들었다. 첫째 함수는 스크립트 실행 이전에 선언을 했고 my_normal_func()라 이름 지었다. 둘째 함수는 create_function()을 호출해서 만들었다. 이 스크립트를 실행하면 함수가 생성되고, 함수의 이름은 $func_name 변수에 저장된다. 그리고 첫째 예제에서 선언했던 함수와 동일한 코드와 매개 변수를 갖게 된다. 이 과정은 콜백 함수나 데이터 검증 함수 등에 유용하다. 실제 코딩을 위해 create_function() 함수를 자세히 알고 싶으면,
php.net 매뉴얼을 참조하자.
결론
PHP를 이용하면, 최소한의 개발 시간으로 훌륭한 결과를 내는 복잡한 프로그램을 만들 수 있다. 하지만 다른 강력한 툴과 마찬가지로, 동적 프로그래밍을 부적절하고 부주의하게 사용하면 심각한 보안상의 허점을 야기할 수 있다. 동적 함수에 기반한 함수를 생성하거나 명령을 실행하기 전에, 사용자가 직접 입력한 동적 코드에 악의적인 코드가 있는지 먼저 검사해야 한다.
존 코그셸(John Coggeshall)은 10년 이상 프리랜서로 웹 컨설턴트와 그래픽 디자인 일을 해 왔으며, PHP를 사용한 지는 5년 남짓 되었다.
이호재(linux96@nownuri.net)님은 한빛 리포터 1기로 활동 중입니다. 카드코리아 개발 실장으로 근무한 경험이 있으며, 지금은 서울대 지구환경시스템공학부(컴퓨터 공학)에 다니고 있습니다. 컴퓨터에 관련된 모든 분야에 두루 관심이 많으며, 요즈음엔 파이썬, MPI, PHP 등에 관심이 많다고 합니다.