가변 변수

가변 변수

변수 이름조차 동적으로 만들어 쓰고 싶을 때가 있죠? 바로 그럴 때 쓰는 게 PHP의 가변 변수(variable variables)예요. 달러 기호를 두 개 붙여 변수 이름 자체를 값으로 다루는 방법을 알아봅니다.

출처: Variable variables

본문

때로는 변수 이름 자체를 동적으로 설정하고 사용할 수 있으면 편리할 때가 있어요. 일반 변수는 다음과 같은 문장으로 설정하죠.

<?php
$a = 'hello';
var_dump($a);

가변 변수(variable variable)는 어떤 변수의 값을 가져와서 그 값을 또 다른 변수의 이름으로 취급해요. 위 예제에서 hello라는 값을 두 개의 달러 기호를 써서 변수 이름으로 사용할 수 있습니다.

<?php
$a = 'hello';
$$a = 'world';
var_dump($hello);

이 시점에 PHP 심볼 트리에 두 개의 변수가 정의되어 저장돼요. $a는 내용이 "hello"이고, $hello는 내용이 "world"입니다. 따라서 다음 문장은

<?php
$a = 'hello';
$$a = 'world';
echo "$a {$$a}";

다음과 완전히 같은 출력을 만들어냅니다.

<?php
$a = 'hello';
$$a = 'world';
echo "$a $hello";

즉 둘 다 hello world를 출력하죠.

가변 변수를 배열과 함께 쓰려면 모호함(ambiguity) 문제를 풀어야 해요. 파서가 $$a[1]을 보면, $a[1]을 변수로 쓰려는 건지 아니면 $$a를 변수로 쓰고 거기에 [1] 인덱스를 붙이려는 건지 알아야 하거든요. 이 모호함을 해결하는 문법은 첫 번째 경우 ${$a[1]}, 두 번째 경우 ${$a}[1]입니다.

클래스 프로퍼티도 가변 프로퍼티 이름으로 접근할 수 있어요. 가변 프로퍼티 이름은 호출이 일어나는 유효범위 안에서 결정됩니다. 예를 들어 $foo->$bar 같은 표현식이 있다면, 로컬 유효범위에서 $bar를 찾아 그 값을 $foo의 프로퍼티 이름으로 사용하죠. $bar가 배열 접근이라 해도 마찬가지예요.

중괄호를 쓰면 프로퍼티 이름을 명확하게 구분할 수도 있어요. 배열을 담고 있는 프로퍼티 안의 값을 접근할 때, 프로퍼티 이름이 여러 부분으로 이뤄졌을 때, 또는 프로퍼티 이름이 다른 방식으로는 유효하지 않은 문자(json_decode()나 SimpleXML에서 온 경우 등)를 포함할 때 특히 유용합니다.

<?php
class Foo {
    public $bar = 'I am bar.';
    public $arr = ['I am A.', 'I am B.', 'I am C.'];
    public $r   = 'I am r.';
}

$foo = new Foo();
$bar = 'bar';
$baz = ['foo', 'bar', 'baz', 'quux'];
echo $foo->$bar . "\n";
echo $foo->{$baz[1]} . "\n";

$start = 'b';
$end   = 'ar';
echo $foo->{$start . $end} . "\n";

$arr = 'arr';
echo $foo->{$arr[1]} . "\n";
echo $foo->{$arr}[1] . "\n";

I am bar.
I am bar.
I am bar.
I am r.
I am B.

참고: 가변 변수는 PHP의 슈퍼글로벌 배열과는 함수나 클래스 메서드 안에서 함께 쓸 수 없다는 점을 주의하세요. $this 변수 역시 동적으로 참조할 수 없는 특별한 변수입니다.

더 알아보기