티스토리 뷰

레퍼런스로 리턴하기

지 난 칼럼에서는 PHP에서 여러 값을 리턴하기 위해 레퍼런스를 함수의 파라미터로 사용하는 방법에 대해 살펴보았다. 이번 칼럼에서는 레퍼런스를 실제 리턴값으로 사용하는 것에 대해 알아보고 이것이 개발자에게 얼마나 유용한지를 알아 볼 것이다. 이번 기사를 위해 다음과 같은 클래스를 만들었다.
<?php
class A {
function printmsg() {
echo "Class is A<br>";
}
}
class B {
function printmsg() {
echo "Class is B<br>";
}
}
$toolbox[] = new A();
$toolbox[] = new B();
?>
위 코드에서 보다시피 A와 B라는 간단한 두 개의 클래스를 생성했다. 그리고 각각은 printmsg()라는 함수 하나만을 포함하고 있다. 그리고 나서, 각 클래스의 인스턴스를 생성했고 $toobox라 는 배열에 저장을 하였다. 우선 위의 것은 넘어가고, 레퍼런스 함수를 통해 전달하는 것부터 알아보자. 여러 곳에서 레퍼런스 함수에 의한 리턴이 쓰일 수 있지만, 여기서 생성할 함수는 오직 하나의 파라미터(이번 경우엔 간단히 하기 위해 불린 값(boolean value)을 사용하였다.)만을 받아들이고, 아래처럼 위에서 생성한 객체중 하나를 가리키는 레퍼런스를 리턴한다.
<?php
function &selectObject($which = false) {
global $toolbox; //위에서 끌어 가지고 오고..
if($which == true)
return $toolbox[0];
return $toolbox[1];
}
$tool =& selectObject(true);
$tool->printmsg();
$anothertool =& selectObject(false);
$anothertool->printmsg();
?>
그렇다면 우리가 만든 selectObject()란 함수는 정확히 어떤 역할을 하는가? 함수 선언을 살펴보면, 이 함수는 파라미터로 하나의 불린 변수(boolean parameter) $which를 사용하고 있다. 그런데 함수 이름 앞에 있는 &는 도대체 무엇일까? 이 기호는 이 함수가 완전한 변수 대신에 PHP 레퍼런스를 리턴한다는 것을 정의한다. 함수 내부의 코드를 살펴보면, 이 함수가 앞에서 이미 정의한 $toolbox 배열에 저장되어 있는 하나의 객체를 리턴하는 것을 알 수 있다. 즉, 파라미터 값에 따라 우리가 정의한 객체중의 하나의 레퍼런스를 리턴하는 것이다.

이제 실제 함수가 어떻게 사용되는지 살펴보도록 하자. 위에서 보았듯이
$tool 변수를 selectObject()가 리턴하는 값으로 초기화하였다. 변수 값을 할당함에 있어 표준 문법을 사용하지 않고 지난번 칼럼에서 소개한 레퍼런스 결합 문법(reference-binding syntax)을 사용했다는 것에 주목하기 바란다. selectObject()가 레퍼런스를 리턴하는 함수이기 때문에 $tool 변수를 레퍼런스 변수로 다루어야 하고 그래서 "=&" 문법을 사용하였다. 일단 적절하게 할당이 되었다면, $tool은 이제 $toolbox 배열의 첫번째 인덱스인 $toolbox[0]를 가리키고 있을 것이고, 이는 클래스 A의 인스턴스를 나타낸다. 같은 방법으로 $anothertool 변수에 클래스 B의 인스턴스를 가리키도록 하였다(여기서는 단순하게 파라미터로 true대신 false
를 전달했음).

위 에서 보인 예제가 그리 실용적으로 보이지 않더라도, 탐색 트리나 다른 복잡한 데이터 구조를 다룰 때에는 레퍼런스를 리턴하는 함수를 사용하는 것이 아주 유용하다. 왜냐하면 개발자는 데이터 구조를 검색하면서 자신이 필요로하는 정확한 데이터 조각의 레퍼런스를 리턴할 수 있기 때문이다.

객체 생성자로써의 레퍼런스

지 금까지 레퍼런스에 관한 거의 모든 것을 다루었다. 이제는 레퍼런스에서 가장 이해하기 어려운 것에 대해 살펴볼 차례이다. 생성자 내에서 객체로의 레퍼런스가 바로 가장 이해하기 어려운 부분 중에 하나인데 다음 클래스를 살펴보면서 알아보기로 하겠다.
<?php
class test {
function test($val) {
global $myref;
$myref = &$this;
$this->value = $val;
}
function printval() {
echo "The value of this class is '{$this->value}' <br>";
}
function setval($val) {
$this->value = $val;
}
}
?>
이 객체의 생성자에서 전역 변수인 $myref$this (PHP에서 정의되어 있는 객체 자신을 가리키는 레퍼런스)를 참조하고 있고, 멤버 변수인 $value가 파라미터 $value 값을 갖는 것에 대해 주목하라. 이 클래스의 인스턴스가 생성될 때, 이 인스턴스를 가리키고 있는 전역 변수 $myref도 또한 생성된다. 따라서 아래와 같은 코드가 실행된다고 하면,
<?php
$myvar = new test('FooBar!');
$myvar->printval();
$myref->printval();
?>
다음과 같이 출력될 것이다.
The value of this class is 'FooBar!'
The value of this class is 'FooBar!'
만약 이 클래스의 인스턴스에서 멤버 변수를 변경하려 한다면 어떻게 될까? 우리가 지금까지 배운 바에 기초하면 $myvar->setval()이나 $myref->setval()를 통한 변경은 두 가지 모두 영향을 줄 것이다. 하지만, 아래와 같은 코드가 실행된다면,
<?php
$myvar->setval('Changed the value from $myvar');
$myvar->printval();
$myref->printval();
?>
결과 값은 다음과 같을 것이다.
The value of this class is 'Change the value from $myvar'
The value of this class is 'FooBar!'
왜 둘 모두의 값이 바뀌지 않았을까? 답은 객체가 처음 생성될 때 있다. PHP 4에서는 new 구문이 기본적으로 레퍼런스를 리턴하지 않는다. 오히려 $myvar 오브젝트가 생성될 때, $myref 변수에 의해 참조되는 것과는 다른 복사본이 리턴된다. 두 개가 같은 객체의 서로 다른 인스턴스이기 때문에, 그들의 변수는 완전히 독립적인 것이다. 이것 말고 우리가 처음에 바랐던 동작을 원한다면, 다음과 같이 객체를 생성할 때 레퍼런스 결합 문법을 사용해야 한다.
<?php
$myvar =& new test('Foobar!');
$myvar->printval();
$myref->printval();
$myvar->setval('Now it works');
$myvar->printval();
$myref->printval();
?>
그리고 출력은 다음과 같다.
The value of this class is 'Foobar!'
The value of this class is 'Foobar!'
The value of this class is 'Now it works'
The value of this class is 'Now it works'

'웹개발 > Php' 카테고리의 다른 글

추상 팩토리 패턴  (0) 2010.12.20
Adapter 패턴  (0) 2010.12.20
PHP 최적화 40가지  (0) 2010.12.20
PHP 참조 반환하기  (0) 2010.12.20
레퍼런스 함수  (0) 2010.12.18
댓글
D-DAY
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함