PHP를 하다보면 간혹 변수앞에 &(엠퍼센트) 부호를 볼 수 가있다. 우리는 언제나 그렇듯 아무생각 없이 그냥 넘어갈때가 있는데 이 부등호는 AND 부등호와는 다르게 주소참조 부등호로 특정 값을 참조할때 사용하는 부등호이다.  조금 더 무식하게 예를 들자면 신용카드를 복제하여 사용할 수 있듯이 기존 변수를 참조시키고 해당 변수값을 변경하면 기존 변수값도 변경되는것과 같다. 

 

먼저 PHP에서 주소참조에 대한 예제소스는 아래와 같다. 

<?php
// 카드정보
$card = array(
	'name'=>'홍길동', // 카드사용자
	'cardnum'=>'1234-5678-9102-3456', // 카드번호
	'totalAmount'=>1000 // 총 사용액
);

// 카드복사 (참조)
$copy_card = &$card;

// 카드사용
$copy_card['totalAmount'] += 5000;
print_r($card); // 출력: Array ( [name] => 홍길동 [cardnum] => 1234-5678-9102-3456 [totalAmount] => 6000 )

 

위의 예제를 보면 $card 변수가 있고 $copy_card에 참조를 시킨 후 참조 변수를 통해 totalAmount 값을 변경한 예제이다. 결과는 당연하게도 totalAmount 값이 6000이 된다. 

 

더 나아가 아래 예제와 같이 참조 변수 뿐만 아니라 기존 변수를 변경하였을 때에도 참조 변수 또한 변경 사항이 반영되는것을 알 수 있다. 

<?php
// 카드정보
$card = array(
	'name'=>'홍길동', // 카드사용자
	'cardnum'=>'1234-5678-9102-3456', // 카드번호
	'totalAmount'=>1000 // 총 사용액
);

// 카드복사 (주소참조)
$copy_card = &$card;

// 카드사용
$copy_card['totalAmount'] += 5000;
print_r($card); // Array ( [name] => 홍길동 [cardnum] => 1234-5678-9102-3456 [totalAmount] => 6000 )

$card['totalAmount'] += 1000;
print_r($copy_card); // Array ( [name] => 홍길동 [cardnum] => 1234-5678-9102-3456 [totalAmount] => 7000 )

 

그럼 여기서 한가지 의문점이 생기는게 기존 변수 $card 가 초기화 될 경우에는 어떻게 되는지 궁금할 수 있다. 예제로 살펴보면 아래와 같다. 

<?php
// 카드정보
$card = array(
	'name'=>'홍길동', // 카드사용자
	'cardnum'=>'1234-5678-9102-3456', // 카드번호
	'totalAmount'=>1000 // 총 사용액
);

// 카드복사 (주소참조)
$copy_card = &$card;

// 카드사용
$copy_card['totalAmount'] += 5000;
$card = array();
print_r($copy_card); // 출력: Array ( )

 

기존 변수가 초기화 될 경우 위의 예제와 같이 참조된 변수또한 초기화 된다. 하지만 이건 언제까지나 초기화 됬을 때 이고 기존 변수 자체를 unset 함수를 통해 파괴했을 때에는 참조된  변수는 그대로 유지가 된다. 

<?php
// 카드정보
$card = array(
	'name'=>'홍길동', // 카드사용자
	'cardnum'=>'1234-5678-9102-3456', // 카드번호
	'totalAmount'=>1000 // 총 사용액
);

// 카드복사 (주소참조)
$copy_card = &$card;

// 카드사용
$copy_card['totalAmount'] += 5000;
unset($card);
print_r($copy_card); // 출력: Array ( [name] => 홍길동 [cardnum] => 1234-5678-9102-3456 [totalAmount] => 6000 ) 

 

이와 반대로 참조된 변수를 unset 함수를 통해 파괴 시킨다면 어떻게 될까? 아래 예제를 살펴보면 알 수 있듯이 이경우에는 참조된 변수만 파괴되고 기존 변수는 그래도 유지된다. 

<?php
// 카드정보
$card = array(
	'name'=>'홍길동', // 카드사용자
	'cardnum'=>'1234-5678-9102-3456', // 카드번호
	'totalAmount'=>1000 // 총 사용액
);

// 카드복사 (주소참조)
$copy_card = &$card;

// 카드사용
$copy_card['totalAmount'] += 5000;
unset($copy_card);
print_r($card); // 출력: Array ( [name] => 홍길동 [cardnum] => 1234-5678-9102-3456 [totalAmount] => 6000 )

 

따라서 참조된 변수를 어느순간 초기화 하고 싶다면 unset 함수를 이용해야 한다. 위의 예제들은 변수를 통해 알아 보았고 그럼 이제 함수에서 사용은 어떻게 되는지 아래의 예제를 확인해보자 

<?php
function copy_var(&$copy_var){
	$copy_var ++;
}
$var = 1;
print_r($var); // 출력: 1 
copy_var($var);
print_r($var); // 출력: 2 

 

위의 예제를 보면 알 수 있듯이 함수 파라미터로 참조 변수를 받기때문에 처음 실행시 에는 1이 출력되고 참조 함수를 실행했을 경우 2가 출력이 된다. 그럼 만약 함수 내에서 unset 함수를 통해 참조변수 자체를 파괴하면 어떻게 될까? 그 결과는 아래 예제와 같이 실제 변수는 파괴되지 않는다. 

<?php
function copy_var(&$copy_var){
	unset($copy_var);
}
$var = 1;
print_r($var); // 출력: 1 
copy_var($var);
print_r($var); // 출력: 1

 

unset 함수 자체가 현재 할당된 주소의 변수를 파괴하기때문에 unset 함수를 사용하면 $copy_var 주소에 할당된 변수만 파괴시키고 $var 주소에 할당된 변수는 파괴시키지 않는다.  

 

추가로 우리가 주로 함수내에서 전역 변수를 사용하기 위해 global 지시어를 붙여서 사용하게 되는데 아래의 예제와 같이 함수 내에서 global을 사용하는건 참조하는것과 동일하다.  

<?php
function copy_var(){
	global $var;
	$var ++;
}
$var = 1;
print_r($var); // 출력: 1 
copy_var($var);
print_r($var); // 출력: 2

 

우리가 사용하는 global 지시어는 함수 내에서 전역변수처럼 사용할 수 있도록 해주는 역활을 하는데 정확하게 본다면 변수 자체는 메모리상 같은 주소에 할당된게 아니다.  즉 함수내에서 지역변수 $var 선언해서 전역변수에 담긴 $var 값을 참조시킨것이기때문에 메모리상에서 변수 자체는 서로 다른 주소에 값이 들어가 있다.   

 

하지만 함수 내에서는 아래의 예제와 같이 슈퍼 전역변수($GLOBALS) 를 통해 초기화가 가능하다. 

<?php
function copy_var(){
	unset($GLOBALS['var']);
}
$var = 1;
print_r($var); // 출력: 1 
copy_var($var);
print_r($var); // 출력: NULL

 

위와 같이 변수 참조에 대해 알아보았는데 실무에서는 사실상 함수내 global 지시어를 많이 사용하지 여러 방면으로 참조 변수를 많이 사용하는 편은 아니다. 사용된다고 하면 간단한 형태의 변수 범위가 아닌 다중 class 와 같은 복잡한 구조에서 최상위 모듈 class 내 $this 객체 자체를 참조 받아서 사용하는 방법인데 즉 1개의 모듈 class 가 있고 밑으로 여러 다중의 class 가 있을 경우 모듈 class 내 $this 변수 연결 고리를 1개로 통합할 수 있는 참조 변수 객체를 만들때 많이 사용한다. 

 

다만 이러한 구조로 class 를 구현하는건 상당히 복잡하기도하고 class 종속 관계에 있어 이해도가 높아야 한다. 구조가 복잡하지 않다면 class 내 순서도를 구성하고 적절한 extends 를 통해 구성하는 방법도 좋다.  뭐 이번편은 class와 관련된 내용이 아니니 여기까지만 하고 넘어가도록 하자.