phpclass/클래스활용2000. 7. 13. 14:04
범위연산자란?
PHP4에서만 지원되며 클래스와 메소드 또는 클래스와 멤버변수를 연결시켜 주는 일로 범위연산자(scope resolver) 뒤에 나오는 메소드와 멤버변수의 스코프(사용범위)를 지정하는 일을 하는 것입니다.
클래스명::메소드명
클래스명::멤버변수명
범위연산자 사용목적
1. 인스턴스되지 않은 클래스의 메소드에 접근할 때
2. 부모클래스의 메소드와 멤버변수에 접근할 때
인스턴스되지 않은 클래스에 있는 메소드에 접근할 때
[code php;gutter:false] class A {
function example() {
echo "클래스 A에 정의된 메소드 example. \n";
}
}

A::example(); [/code]
아직 클래스 A에 대한 객체가 생성되기 전이지만 범위연산자를 이용하면 일반 함수처럼 실행시킬 수 있습니다. 그러나 클래스 A에 대한 객체가 전혀 생성되어 있지 않으므로 클래스 외부에서 이 함수에 접근할 때는 이 함수 내에 $this 객체를 사용해서는 안됩니다. 물론 일반 함수와 마찬가지로 지역 변수 및 전역 변수를 사용할 수는 있습니다.
[code php;gutter:false] class A {
var $var = "초기값";

function example() {
echo "클래스 A에 속한 메소드 example. \n";
echo $this->var . "\n";
}
}

A::example(); [/code]
위의 예제를 보면 아직 클래스 A에 대한 객체가 생성되지 않았으므로 멤버변수 $var에 대한 기억장소가 할당되지도 않았고 더구나 초기값을 설정할 수도 없습니다. 그러니 아무리 범위연산자를 이용하여 메소드 example()에 접근한다해도 멤버변수 $var의 초기값을 나타낼 수는 없을 것입니다. 실험해 본 바로는 이 경우 $this->var의 값이 NULL로 처리되는 것 같습니다.
부모클래스의 메소드에 접근할 때
[code php;gutter:false] class A {
function example() {
echo "클래스 A에 정의된 메소드 example. \n";
}
}

class B extends A {
function example() {
echo "클래스 B에서 재정의된 메소드 example. \n";
A::example();
}
}

$b = new B;

$b->example(); [/code]
이 예의 출력결과를 보면 아래와 같이 나타날 것입니다.
클래스 B에서 재정의된 메소드 example.
클래스 A에 정의된 메소드 example.
범위연산자는 클래스가 상속되었을 때 재정의되기 전의 부모클래스에 있는 메소드에 접근할 때 유용하게 사용될 수 있습니다.
부모클래스의 멤버변수에 접근할 때
php.net의 문서 설명과는 달리 아직 공개되지 않는 어떤 방법이 있는 지는 모르겠으나 부모클래스의 멤버변수로 접근하는 방법에 대하여는 문서화되지 않은 것 같습니다.

Posted by 방글24
phpclass/클래스활용2000. 7. 13. 14:03
생성자(constructor)는 클래스의 새로운 인스턴스가 생성될 때 자동적으로 호출되는 클래스 내의 함수이며, 클래스명과 동일한 이름를 갖는 특수한 메소드입니다.
[code php;gutter:false] class Cart {
var $items; // Items in our shopping cart

// Add $num articles of $artnr to the cart

function add_item ($artnr, $num) {
$this->items[$artnr] += $num;
}

// Take $num articles of $artnr out of the cart

function remove_item ($artnr, $num) {
if ($this->items[$artnr] > $num) {
$this->items[$artnr] -= $num;
return true;
} else {
return false;
}
}
}

class Auto_Cart extends Cart {
function Auto_Cart () {
$this->add_item ("10", 1);
}
} [/code]
위의 예제는 클래스 Auto_Cart가 new 연산자로 만들어질 때마다 품목번호 "10"의 수량이 1을 갖도록 장바구니를 초기화시키는 생성자를 새로이 포함하여 정의하였습니다.
생성자에 전달되는 인자
생성자는 필요하면 선택적으로 인자(argument)를 전달할 수도 있기 때문에 매우 유용하게 사용됩니다.
[code php;gutter:false] class Constructor_Cart extends Cart {
function Constructor_Cart ($item = "10", $num = 1) {
$this->add_item ($item, $num);
}
}

// Shop the same old boring stuff.

$default_cart = new Constructor_Cart;

// Shop for real...

$different_cart = new Constructor_Cart ("20", 17); [/code]
PHP3와 PHP4 생성자 사이에 발생하는 미묘한 차이
PHP3에서는 클래스와 동일한 이름을 가진 함수를 생성자로 처리하고 있습니다. 따라서 아래와 같은 경우에 클래스 B의 이름과 동일한 이름의 함수 B()가 없으므로 객체를 생성할 때 실행할 생성자가 없습니다.
[code php;gutter:false] class A {
function A() {
echo "I am the constructor of A.\n";
}
}

class B extends A {
function C() {
echo "I am a regular function.\n";
}
}

// no constructor is being called in PHP3.
$b = new B; [/code]
그러나 만약 아래와 같이 클래스 A에 함수 B()가 정의되어 있다면 설사 클래스 B를 가지고 객체를 생성하더라도 클래스 A에 있는 일반함수 B()를 클래스 B의 생성자로 인식합니다. 즉, PHP3에서는 함수 B()가 클래스 B에 속해 있는지 아니면 부모 클래스로부터 상속된 함수인지를 인식하지 못합니다. 따라서 객체 $b를 생성할 때 클래스 A에 있는 일반함수 B()를 생성자로써 실행하게 되는 것이지요.
[code php;gutter:false] class A {
function A() {
echo "I am the constructor of A.\n";
}

function B() {
echo "I am a regular function named B in class A.\n";
echo "I am not a constructor in A.\n";
}
}

class B extends A {
function C() {
echo "I am a regular function.\n";
}
}

// no constructor is being called in PHP3.
$b = new B; [/code]
클래스 B에 속하지도 않은, 부모클래스로부터 상속된 일반 함수 B()를 클래스 B의 생성자로 인식한다는 것은 대부분 우리가 전혀 의도하지 않는 일로 잘못하다가는 원치않는 결과를 초래할 수도 있습니다. 객체지향언어에서 말하는 생성자의 구분이 모호해 진다는 것이지요. 이러한 문제를 PHP4에서는 바로 잡았습니다. 단지 이름만 같다고 생성자로 처리하는 것이 아니라 반드시 해당 클래스 내에 포함되어 있는 것만 생성자로 처리하도록 수정하였습니다. 따라서 위의 예를 PHP4에서 수행한다면 클래스 A에 속한 일반함수 B()를 생성자로써 실행하지는 않습니다.
대신에 PHP4에서는 생성자와 관련하여 새로운 기능이 추가되었습니다. 파생클래스에서 생성자가 정의되어 있지 않으면 그 부모 클래스에 정의된 생성자가 실행하도록 수정되었습니다. 즉, 위의 예에서보면 객체 $b를 생성할 때 클래스 B에 해당하는 생성자 B() 함수가 정의되어 있지 않으므로 그 부모 클래스의 생성자인 A()가 생성자로 수행됩니다.
이러한 PHP3와 PHP4 사이의 미묘한 차이를 명확히 구분하지 못한 상태에서 생성자를 다루게 되면 프로그램이 매우 심각한 오류에 빠질 수 있다는 것을 참고하시기 바랍니다.

Posted by 방글24
phpclass/클래스활용2000. 7. 13. 14:02
클래스를 상속하려면?
기존에 이미 작성된 클래스를 상속(class inheritance)받으면 이미 작성된 메소드와 멤버변수를 그대로 이어받게 됩니다. 상속받은 특성에 덧붙여 새로운 특성을 추가하는 방법으로 새로운 클래스를 정의하게 됩니다. 이와 같이 기존의 클래스로부터 특성을 이어받는 것을 상속이라고 합니다. 이 때 확장된 클래스를 정의하기 위해 "extends"라는 키워드를 사용합니다.
부모클래스 & 자식클래스에 관련된 용어
기존의 클래스와 확장된 클래스를 나타내는 용어는 객체지향언어마다 다양하게 사용되고 있습니다. 그러나 어떤 용어를 사용하더라도 같은 의미로 사용되고 있다고 이해하시면 됩니다.
기존의 클래스 확장된 클래스
용어 영문 용어 영문
기반클래스 base class 파생클래스 derived class
수퍼클래스 super class 서브클래스 sub class
부모클래스 parent class 자식클래스 child class
클래스 상속 예제
[code php;gutter:false] class Cart {
var $items; // Items in our shopping cart

// Add $num articles of $artnr to the cart

function add_item ($artnr, $num) {
$this->items[$artnr] += $num;
}

// Take $num articles of $artnr out of the cart

function remove_item ($artnr, $num) {
if ($this->items[$artnr] > $num) {
$this->items[$artnr] -= $num;
return true;
} else {
return false;
}
}
}

class Named_Cart extends Cart {
var $owner;

function set_owner ($name) {
$this->owner = $name;
}
} [/code]
클래스 Named_Cart는 클래스 Cart의 모든 변수와 함수를 그대로 상속받게 되며, 새로운 멤버인 변수 $owner과 함수 set_owner()를 추가하여 정의합니다. 앞서 배운 new 연산자를 이용하여 클래스 Named_Cart의 객체를 생성한 후 장바구니 주인을 지정하거나 주인이 누구인지 확인할 수 있습니다. 아울러 부모클래스 Cart에 있는 장바구니 관련 함수를 그대로 사용할 수 있습니다.
[code php;gutter:false] $ncart = new Named_Cart; // Create a named cart
$ncart->set_owner ("kris"); // Name that cart
print $ncart->owner; // print the cart owners name
$ncart->add_item ("10", 1); // (inherited functionality from cart) [/code]
단일 상속
PHP는 다중 상속(multiple inheritance)를 지원하지 않으며, 오로지 단일 상속만 지원합니다.

Posted by 방글24
phpclass/클래스활용2000. 7. 13. 14:00
객체 생성=객체 초기화(object initialization)=인스턴스화(instantiation)
클래스는 붕어빵을 만드는 틀(= type, =template)과 같은 것으로, 클래스 내에 정의된 메소드와 멤버변수를 사용하기 위해서는 틀을 가지고 붕어빵을 만드는 것같이 객체를 생성하여야 합니다. 객체(object)를 초기화하는 방법은 new 연산자를 사용하여 객체를 변수에 인스턴스 시키는 것입니다.
[code php;gutter:false] class Cart {
var $items; // Items in our shopping cart

// Add $num articles of $artnr to the cart

function add_item ($artnr, $num) {
$this->items[$artnr] += $num;
}

// Take $num articles of $artnr out of the cart

function remove_item ($artnr, $num) {
if ($this->items[$artnr] > $num) {
$this->items[$artnr] -= $num;
return true;
} else {
return false;
}
}
}

$cart = new Cart;
$cart->add_item("10", 1); [/code]
위와 같이 하면 클래스 Cart에 대한 객체 $cart가 생성됩니다. 객체 함수 add_item()은 장바구니에 품목번호 "10"의 수량을 1개 추가하기 위해 호출됩니다.
지정연산자 "->"의 의미
"->" 는 객체의 멤버변수 또는 메소드를 지정하는데 사용되는 지정연산자입니다. C++ 언어를 접해 본 분은 쉽게 이해하시겠지만, new 연산자로 생성되는 객체를 나타내는 객체명에는 실제로 객체의 멤버(변수 또는 함수)가 존재하는 것이 아니라 객체의 멤버가 존재하는 메모리상에 위치를 나타내는 주소(adress)가 담겨져 있습니다. 이와 같이 객체지향언어에서는 주소를 가지고 멤버를 참조하려면 아래와 같이 지정연산자 "->"를 이용하게 됩니다.
멤버변수를 참조할 때 : 객체명->변수;
메소드를 참조할 때 : 객체명->함수;
C++ 언어에서는 "->"를 화살표 멤버 연산자라고 말하며, "->"의 앞쪽에 있는 식별자(여기서는 객체명)가 포인터(pointer; 주소를 의미함)일 때 그 멤버를 참조하기 위한 연산자입니다.
지역 변수에 초기화된 객체
객체를 지역변수에 인스턴스할 수 있기 때문에, 클래스를 정의하고 객체를 생성하는 것을 하나의 모듈로 개발할 수 있습니다.
[code php;gutter:false] <?php

function class_in_function() {
class test {
var $a = 10;
function test() {
echo "함수 내에 정의된 클래스의 생성자 실행\n";
}
function echo_test() {
echo "함수 내에 정의된 클래스의 멤버변수 \$a의 값 = ".$this->a."\n";
}
}

$obj = new test;
$obj->echo_test();
}

class_in_function();
?> [/code]
< 예제 코드 >
함수 내에 정의된 클래스의 생성자 실행
함수 내에 정의된 클래스의 멤버변수 $a의 값 = 10
< 실행 결과 >
객체 생성할 때 생성자명을 가변함수로 지정하기
[code php;gutter:false] $classname = "MiniDB";
$obj = new $classname(); [/code]
이 코드는 PHP3와 PHP4 모두에서 정상적으로 동작합니다.
메소드명을 변경하기(가변함수)
PHP의 매뉴얼을 보면 가변함수(variable function)를 지원하는데 이것은 변수명 뒤에 괄호가 왔을 때, PHP는 그 이름을 가진 함수를 찾아 실행하는 것입니다. 이것은 클래스의 메소드에서도 그대로 사용할 수 있습니다.
[code php;gutter:false] class test {
function A() {
echo "나 A 함수\n";
}
}

$obj = new test;

$method = "A";
$obj->$method(); [/code]
이것을 응용하여 같은 실행문으로 A0, A1, A2라는 메소드에 번갈아 가면서 접근하려면 역시 가변함수를 사용하면 됩니다.
[code php;gutter:false] class test {
function A0() {
echo "나 A0 함수\n";
}

function A1() {
echo "나 A1 함수\n";
}
function A2() {
echo "나 A2 함수\n";
}
}

$obj = new test;

for ($i=0;$i<3;$i++) {
$method = "A$i" ;
$obj->$method();
} [/code]
위에 것은 모두 PHP3와 PHP4에서 모두 동작되는 코드입니다. 만약, PHP4에서만 동작시켜도 무방하다면 아래와 같이 중괄호를 이용하면 소스를 간결하게 코딩할 수 있습니다.
[code php;gutter:false] for ($i=0;$i<3;$i++) {
$obj->{"a$i"}();
} [/code]
객체명을 변경하기(가변변수)
가변변수(Variable Variables)의 유용함은 모두 알고 있겠지만 PHP4에서는 별문제가 없지만 PHP3에서 객체변수를 가변변수로 사용하기는 그리 쉽지 않습니다.
[code php;gutter:false] class test {
var $hello = "hello world";
}

$obj = new test;
$a = "obj";
echo $$a->hello; // or echo ${$a}->hello; [/code]
PHP3에서 위와 같이 작성하여 실행한다면,
Object
Parse error: parse error, ...... test.php3 on line 9
위와 같은 에러를 만나게 됩니다. 그러나 PHP4에서는 객체변수에도 가변변수를 제대로 지원하기 시작했습니다. 따라서 위의 예제가 에러없이 잘 실행되지요. 그러면 PHP3에서는 객체변수의 이름을 변경할 수 없을까요? 아래와 같이 $GLOBALS 배열을 사용해 보세요. 아무 문제없이 잘 실행될 겁니다.
[code php;gutter:false] class test {
var $hello = "hello world";
}

$obj = new test;
$a = "obj";
echo $GLOBALS[$a]->world(); [/code]
따라서 PHP3와 PHP4 모두에서 동작되기를 바란다면 $GLOBALS 배열을 이용하여 작성하세요.
배열구조의 멤버변수를 가변변수로 다루는 방법
[code php;gutter:false] class test {
var $arr = array();

function test() {
$this->arr[0] = 0;
$this->arr[1] = 1;
}
}

$obj = new test; [/code]
위와 같이 클래스 test에 배열 구조의 멤버변수가 있을 때, 이러한 멤버변수의 배열 요소에 접근하려면 $obj->arr[0]; 와 같이 사용하면 됩니다. 여기서 멤버변수명 "arr"을 가변변수로 처리하려면,
[code php;gutter:false] $prop = "arr";
$obj->{"$prop"}[0]; [/code]
위와 같이 가변변수 $prop를 중괄호로 묶어주세요. 여기서 겹따옴표는 생략해도 됩니다. PHP3와 PHP4에서 모두 잘 동작할 것입니다.

Posted by 방글24
phpclass/클래스활용2000. 7. 13. 13:50
PHP에서 클래스를 사용하는 방법에 대하여 알아봅니다.
클래스란?
클래스는 객체의 변수와 함수를 정의하는 템플릿이며, 이에 따라 변수로 표현되는 데이터 영역과 이러한 데이터 영역에 접근할 수 있는 함수로 구성됩니다. 클래스 내에 정의된 변수를 멤버변수(member variable)라고 하고 함수를 메소드(method)라고 합니다. C++과 같은 객체지향언어에서는 멤버변수를 데이터멤버, 메소드를 멤버함수라고 호칭합니다. PHP에서 클래스를 사용하는 것은 C++ 또는 자바와 거의 비슷합니다.
클래스 정의
클래스를 정의(class definition)할 때는 키워드 "class"를 사용합니다. 클래스를 구성하는 멤버변수와 메소드를 정의할 때는 "var"과 "function"이라는 키워드를 사용합니다. "function"은 일반 함수를 정의할 때도 사용되지만 "var"은 클래스의 멤버변수를 정의할 때만 사용되는 키워드로, 멤버변수를 정의할 때는 반드시 명시하여야 합니다. 예를 들어 클래스는 아래와 같이 정의합니다. 이 예는 PHP 매뉴얼에 있는 것으로 수정하지 않고 가져왔습니다. 이 예에서는 $items라는 멤버변수와 add_item, remove_item라는 메소드가 정의되어 있습니다.
[code php;gutter:false] class Cart {
var $items; // Items in our shopping cart

// Add $num articles of $artnr to the cart

function add_item ($artnr, $num) {
$this->items[$artnr] += $num;
}

// Take $num articles of $artnr out of the cart

function remove_item ($artnr, $num) {
if ($this->items[$artnr] > $num) {
$this->items[$artnr] -= $num;
return true;
} else {
return false;
}
}
} [/code]
멤버변수의 초기화
PHP3에서는 멤버변수값을 아래와 같이 상수 또는 변수를 이용하여 초기화할 수 있습니다.
[code php;gutter:false] class Cart {
var $items = 0; // Items in our shopping cart
} [/code]
< 상수로 초기화할 때 >
[code php;gutter:false] class Cart {
var $items; // Items in our shopping cart

function Cart($items) {
$this->items = $items;
}
} [/code]
< 변수로 초기화할 때(1) >
[code php;gutter:false] $items = 0;

class Cart {
var $items = $GLOBALS["items"]; // Items in our shopping cart
} [/code]
< 변수로 초기화할 때(2) >
반면 PHP4에서는 var 변수에는 상수로만 초기화할 수 있고, 상수가 아닌 값을 가지고 초기화할 때는 생성자를 이용하여야 합니다. 즉, var $items = $GLOBALS["items"];와 같은 표현은 허용하지 않습니다.
따라서 아래와 같은 표현은 PHP4에서는 허용하지 않습니다.
[code php;gutter:false] class Cart {
var $todays_date = date("Y-m-d");
var $name = $firstname;
var $owner = 'Fred ' . 'Jones';
var $items = array("VCR", "TV");
} [/code]
PHP4에서 초기화할 때 동일한 결과를 얻으려면 아래와 같이 생성자를 이용합니다.
[code php;gutter:false] class Cart {
var $todays_date;
var $name;
var $owner;
var $items;

function Cart() {
$this->todays_date = date("Y-m-d");
$this->name = $GLOBALS['firstname'];
/* etc. . . */
}
} [/code]
PHP4 예약어
stdClass
stdClass 는 Zend에서 내부적으로 사용하고 있는 예약어입니다. 따라서 사용자는 클래스명으로 stdClass를 사용할 수 없습니다. get_declared_classes() 함수를 사용하면 현재 스크립트에 정의된 클래스명을 배열에 담아 되돌려 줍니다. 따라서 이 함수를 이용하면 stdClass의 존재를 확인할 수 있습니다.
[code php;gutter:false] <?php

class Vegetable {

}

class Spinach extends Vegetable {

}

$arr_class = get_declared_classes();

while (list($k,$v)=each($arr_class)) {
echo("\$arr_class[$k]=$v\n");
}

?> [/code]
이 문서를 실행하면 아래와 같은 결과를 얻을 수 있습니다.
[code php;gutter:false] $arr_class[0]=stdClass
$arr_class[1]=OverloadedTestClass
$arr_class[2]=Directory
$arr_class[3]=OCI-Lob
$arr_class[4]=vegetable
$arr_class[5]=spinach [/code]
위 예제의 실행결과를 보면, 사용자가 정의한 vegetable, spinach 외에도 stdClass, OverloadedTestClass, Directory, OCI-Lob가 있는 것을 볼 수 있습니다. 좀 더 자세한 것은 메뉴 "클래스&객체 함수 >> get_declared_classes()"를 살펴보시기 바랍니다.
매직함수(magic function)
__sleep, __wakeup과 같이 "__"로 시작하는 매직함수는 PHP 클래스 내에서 특수한 목적으로 사용됩니다. 따라서 이 함수들이 가지고 있는 문서화된 매직 기능을 사용할 필요가 없다면 클래스 내에 이 함수들을 정의해서는 안됩니다. 자세한 것은 메뉴에서 "매직함수"장을 살펴보기 바랍니다.
$this가 무엇에 쓰는 물건인고?
클래스 메소드 내에서만 사용되며, 클래스의 현재 인스턴스를 참조할 때 사용하는 변수이며, 예를 들어 현재 객체 내에 something라고 명명된 임의의 변수 또는 함수를 참조하기 위해서는 $this->something을 사용하여야 합니다. 즉, "$this"의 의미는 new 연산자에 의해 생성될 객체 자신을 의미합니다. 그러니 아직 생성되지 않은 객체 자신을 의미하는 의사(擬似)변수(pseudo variable)이며, "my own" 또는 "current object"라고 불리웁니다.
앞에서 클래스를 붕어빵 틀과 같다고 했습니다. 정의된 클래스에 의해 생성된 객체는 붕어빵 틀로 만들어낸 수많은 붕어빵이지요. 아래 예에서 본다면, $붕어빵1->make("특급밀가루")으로 make() 메소드에 접근한다면 이 때 make() 메소드 내의 $this는 $붕어빵1을 의미하고, $붕어빵2->make("중급밀가루")으로 접근한다면 이 때 $this는 $붕어빵2를 의미하고, $붕어빵3->make("저급밀가루")으로 접근한다면 이 때 $this는 $붕어빵3을 의미합니다.
[code php;gutter:false] class 붕어빵 {
var 재료;

function make($재료) {
$this->재료 = $재료;
......
}
}

$붕어빵1 = new 붕어빵; // 인스턴스 "붕어빵1"
$붕어빵2 = new 붕어빵; // 인스턴스 "붕어빵2"
$붕어빵3 = new 붕어빵; // 인스턴스 "붕어빵3"

$붕어빵1->make("특급밀가루");
$붕어빵2->make("중급밀가루");
$붕어빵3->make("저급밀가루"); [/code]

Posted by 방글24
phpclass/클래스활용2000. 6. 12. 14:55
정적 데이터멤버란?
생성된 모든 인스턴스들이 공유하는 공통적인 정보가 필요할 때에 사용되는 것이 정적 데이터멤버(static data member)입니다. 정적 데이터멤버는 다른 일반 데이터 멤버와 달리 각각의 인스턴스에 기억장소가 할당되는 것이 아니라, 단 한 개의 기억장소만이 할당되고 모든 인스턴스에 의하여 공유됩니다. 하지만 데이터 멤버의 정보는 각각의 인스턴스가 모두 가지고 있는 것처럼 간주됩니다. 이와 같이 모든 인스턴스에서 공유하는 데이터 멤버를 정적 데이터 멤버로 선언하므로 써, 모든 인스턴스에서 중복되는 기억장소를 절약하는 효과를 얻을 수 있습니다. 때에 따라서는 동일한 클래스 또는 이를 상속한 클래스를 이용해 몇 개의 인스턴스를 생성하더라도 동일한 데이터로 취급해야 할 데이터멤버가 때로는 필요하지요.
PHP3, PHP4 모두 정적 데이터멤버를 지원하지 않습니다.
현재 PHP 스크립트로 정적 데이터멤버의 기능을 구현하려면 전역변수를 이용하여야 합니다. PHP에서는 정적 데이터멤버를 지원하지 않기 때문에 이를 표현할 수 없지만 static 키워드로 표현할 수 있다고 가정하고 예제소스를 작성해 보겠습니다.
[code php;gutter:false] class cls경리부 {
static $수입금액=0;
// php에서 static은 정적변수를 나타내는 키워드이나
// 여기서는 정적 데이터멤버를 나타낸다고 가정하였음

function add_수입금액($income) {
$this->수입금액 += $income;
}
}

class cls판매부 extends cls경리부 {
var $판매금액;

function add_판매금액($income) {
$this->판매금액 += $income;
$this->add_수입금액($income);
}
}

$화장품판매부 = new cls판매부;
$자동차판매부 = new cls판매부;

$화장품판매부->add_판매금액(40000);
$자동차판매부->add_판매금액(20000); [/code]
동일한 클래스 cls판매부를 이용하여 $화장품판매부와 $자동차판매부에 대한 객체를 별도로 생성합니다. 부모클래스인 cls경리부의 데이터멤버 $수입금액은 모든 객체에서 공용으로 사용하려는 데이터멤버입니다. "$화장품판매부->판매금액"과 "$자동차판매부->판매금액"은 별도의 인스턴스로 처리되어 독립적으로 관리되어지나 경리부에서 집계하는 수입금액은 각 판매부에서 판매된 판매금액이 누적되는 값으로 모든 인스턴스가 공유해야 하는 데이터입니다. 이럴 때 수입금액을 정적 데이터멤버로 정의하여 사용하면 편리하지요.
위의 예에서 실행결과는(진짜 실행되는 것은 아니지만 실행된다면), 자동차판매부의 데이터멤버 $판매금액에는 "20,000"원이 저장되고, 화장품판매부의 데이터멤버 $판매금액에는 "40,000"원이 저장되고, 경리부에 최종 집계되는 데이터멤버 $수입금액에는 "60,000"원이 저장됩니다.
정적 데이터멤버를 흉내내기
PHP 에서는 수입금액과 같이 모든 인스턴스에서 공유해야하는 정적 데이터멤버를 정의할 수 없습니다. 따라서 클래스에서 정적 데이터멤버를 흉내내기 위한 기술이 필요합니다. 방법이야 아이디어에 따라 여러가지가 있겠지만 현재까지 제가 알고 있는 방법에는 아래와 같이 네 가지 정도가 있습니다.
1. 후키라이브러리에서처럼 별도의 파서를 라이브러리화하여 사용하는 방법
2. 전역변수를 이용하는 방법
3. 정적변수를 이용하는 방법
4. 클래스를 이용하는 방법
5. 객체 및 정적변수를 이용하는 방법(가장 개선된 방법)
첫번째 방법은 제가 공개한 후키라이브러리를 참고하시기 바랍니다. 사실 첫번째 방법은 1차적으로 파서가 동작된다뿐이지 2차적으로는 두번째, 세번째 또는 네번째 방법을 이용하여 정적 데이터멤버를 구현합니다.
전역변수를 이용하여 정적 데이터멤버를 흉내내기
전역변수를 이용하면 다루기는 무척 간단하고 쉽습니다. 문제는 객체지향프로그래밍의 장점인 정보은닉(information hiding)가 전혀 이루어질 수 없다는 것입니다. 즉, 전역변수(명)를 잘 관리하지 않으면 페이지 내의 다른 부분(전역변수)과 충돌을 일으킬 수 있습니다. 이 것만 주의한다면 다루기에는 무지 편합니다. 위의 예제소스를 전역변수를 이용하여 실제 PHP에서 실행할 수 있는 코드로 바꾸어 보겠습니다.
[code php;gutter:false] $수입금액 = 0; // 전역변수

class cls경리부 {
function add_수입금액($income) {
$GLOBALS[수입금액] += $income;
}
}

class cls판매부 extends cls경리부 {
var $판매금액;

function add_판매금액($income) {
$this->판매금액 += $income;
$this->add_수입금액($income);
}
}

$화장품판매부 = new cls판매부;
$자동차판매부 = new cls판매부;

$화장품판매부->add_판매금액(40000);
$자동차판매부->add_판매금액(20000); [/code]
여기서는 "cls경리부" 클래스만 수정하면 되는데, 우선 "static $수입금액=0;" 대신에 클래스 정의 외부(main body 부분)에 $수입금액을 전역변수로 선언해준 후 전역변수로써 $수입금액을 다루면 됩니다. 비교적 간단하지만 위에서 언급했듯이 "$수입금액"이라는 전역변수를 다른 곳에서 사용하지 말라는 법이 없으니까 변수명을 정할 때 주의하셔야 합니다.
정적변수를 통해 정적데이터멤버를 흉내내기
정적 데이터멤버와 같이 모든 객체가 공유할 수 있는 변수를 사용하려면 현재는 전역변수를 이용할 수 밖에 없는데, 만약 모든 객체가 공유할 변수가 하나밖에 없다면 위와 같이 메소드를 작성하여 이 메소드를 통해 변수를 다루어도 될 것 같습니다. OOP에서 전역변수 사용에 알레르기가 있다면 PHP에서 공식적으로 정적 데이터멤버를 지원할 때까지는 차선책으로 이 방법도 괜찮을 것 같네요. 아래는 사용하는 예입니다.
[code php;gutter:false] <?php

class test {
function statics($val="") {
static $stat;
if ($val)
$stat = $val;
else
echo "var[$stat]\n";
}
}

$obj1 = new test;
$obj2 = new test;

$obj1->statics("obj1에서 기록함");
$obj2->statics();
$obj2->statics("obj2에서 기록함");
$obj1->statics();

?> [/code]
< 소스 코드(test.php3) >
var[obj1에서 기록함]
var[obj2에서 기록함]
< 실행결과 >
이 방법은 PHP4에서만 가능합니다. 그리고 PHP4에서도 동일한 클래스명으로 객체화하였을 때만 제대로 동작됩니다. 만약 동일할 클래스를 상속받은 다른 클래스명으로 객체화 한 경우에는 제대로 동작되지 않습니다.
PHP3 에서 PHP4로 수정하면서 static의 문제(사실은 클래스 문제였다고 할 수 있음)를 손본것 같은데 완벽하게는 손보지 못한 것 같네요. 즉, 멤버함수는 정적 데이터멤버와 같이 객체가 아닌 클래스에 속하여서 작동하게 되는데 상속된 클래스에서 객체화 하는 경우에는 이 부분의 처리가 좀 미숙한 것 같네요. 아래가 이러한 경우의 예입니다. 보시면 obj3의 멤버함수와 obj1,obj2의 멤버함수 사이의 관계가 좀 별다른 것 같네요. 아니면 멤버함수는 동일하게 사용하는데 그 안에 있는 정적변수만 다르게 처리하던지요. 아무튼 이 부분만 주의하여 사용하시기 바랍니다.
[code php;gutter:false] <?php

class test {
function statics($val="") {
static $stat;
if ($val)
$stat = $val;
else
echo "var[$stat]\n";
}
}

class test2 extends test {
}

$obj1 = new test;
$obj2 = new test;
$obj3 = new test2;

$obj1->statics("obj1에서 기록함");
$obj2->statics();
$obj3->statics();
$obj2->statics("obj2에서 기록함");
$obj1->statics();
$obj3->statics();
$obj3->statics("obj3에서 기록함");
$obj1->statics();
$obj2->statics(); [/code]
< 소스 코드(test.php3) >
var[obj1에서 기록함]
var[]
var[obj2에서 기록함]
var[]
var[obj2에서 기록함]
var[obj2에서 기록함]
< 실행결과 >
클래스를 이용하여 정적 데이터멤버를 흉내내기(1)
static 키워드를 사용할 수 없기 때문에 직관적으로 정적 데이터멤버를 다룰 수는 없고 또 다소 복잡한 면이 있지만 객체지향프로그래밍의 핵심 기술인 정보은폐를 어느 정도 보상받을 수 있다는 면에서 추천할 만한 방법이 되겠습니다.
[code php;gutter:false] <?php

class cls경리부 {
var $수입금액 = 0;

function add_수입금액($income) {
$this->수입금액 += $income;
}
}

class cls판매부 {
var $판매금액;
var $objname;

function cls판매부($objname="") {
global $$objname;
if (!is_object($$objname) && $objname) {
$$objname = new cls경리부;
}
$this->objname = $objname;
}

function add_판매금액($income) {
$this->판매금액 += $income;
$GLOBALS[$this->objname]->add_수입금액($income);
}
}

$화장품판매부 = new cls판매부("경리부");
$자동차판매부 = new cls판매부("경리부");

$화장품판매부->add_판매금액(40000);
$자동차판매부->add_판매금액(20000);

echo "각 판매부별 판매금액 누계\n";
echo "-------------------------\n";
echo "화장품판매부 : $화장품판매부->판매금액"."원\n";
echo "자동차판매부 : $자동차판매부->판매금액"."원\n";
echo "\n";
echo "총 판매금액 누계\n";
echo "----------------\n";
echo "전 부서 판매금액 : $경리부->수입금액"."원\n";

?> [/code]
< 소스 코드(test.php3) >
각 판매부별 판매금액 누계
-------------------------
화장품판매부 : 40000원
자동차판매부 : 20000원

총 판매금액 누계
----------------
전 부서 판매금액 : 60000원
< 실행결과 >
가장 핵심적인 부분이 cls판매부의 생성자입니다. 생성자에서 정적 데이터멤버를 흉내낼 수 있는 기반을 닦아 놓지요. 생성자가 인수로 입력받는 것이 정적 데이터멤버(?)가 있는 클래스를 객체 생성할 객체의 변수명입니다. 클래스 내에서 정적 데이터멤버(?)에 접근하는 방법은 아래와 같습니다.
[code php;gutter:false] $GLOBALS[$this->objname]->add_수입금액($income);
$GLOBALS[$this->objname]->수입금액; [/code]
클래스를 이용하여 정적 데이터멤버를 흉내내기(2)
위의 방법보다 훨씬 직관적이고 단순하며 의미가 명료하게 정적 데이터멤버를 흉내내는 방법입니다.
[code php;gutter:false] <?php

class cls경리부 {}

class cls판매부 {
var $경리부;
var $판매금액;
var $objname;

function cls판매부($objname="") {
$this->경리부 = & new cls경리부;
}

function add_판매금액($income) {
$this->판매금액 += $income;
$this->경리부->수입금액 += $income;
}
}

$화장품판매부 = new cls판매부("경리부");
$자동차판매부 = new cls판매부("경리부");

$화장품판매부->add_판매금액(40000);
$자동차판매부->add_판매금액(20000);

echo "각 판매부별 판매금액 누계\n";
echo "-------------------------\n";
echo "화장품판매부 : $화장품판매부->판매금액"."원\n";
echo "자동차판매부 : $자동차판매부->판매금액"."원\n";
echo "\n";
echo "총 판매금액 누계\n";
echo "----------------\n";
echo "전 부서 판매금액 : $화장품판매부->경리부->수입금액"."원\n";

?> [/code]
< 소스 코드(test.php3) >
클래스 cls판매부의 생성자에서 경리부를 정적 데이터멤버(또는 정적 멤버함수)로 처리하였기 때문에 마지막 문장에서 "$화장품판매부"를 통해도 되고 아니면 아래와 같이 "$자동차판매부"를 통해도 됩니다.
[code php;gutter:false] echo "전 부서 판매금액 : $자동차판매부->경리부->수입금액"."원\n"; [/code]
객체 및 정적변수를 이용하여 정적데이터멤버를 흉내내기
정적변수만을 이용하는 방법에서의 문제점은 최하위 상속 클래스가 다를 때 정적변수가 제대로 동작하지 않는다는 것입니다. 이 문제점을 개선하기 위하여 최상위 클래스에 정적변수를 설치하지 않고 별도의 클래스로 정의된 곳에 정적변수를 설치하는 것입니다.
[code php;gutter:false] <?php

/*
실험환경:PHP 4.1.1 (Windows 98)
*/

class hStatic {
function hStatic(&$obj) {
static $static; // 정적 변수 설치
$obj->STATIC = & $static; // 객체에서 사용한 정적 데이터 멤버 설치
}
}

class hTest {
function hTest() {
new hStatic($this); // 정적 데이터 멤버를 위한 클래스의 객체화
}
}

class hTestExt extends hTest {
function hTestExt() {
$this->hTest(); // 부모 클래스의 생성자 실행
}
}

class hTestExt2 extends hTestExt {
function hTestExt2() {
$this->hTestExt(); // 부모 클래스의 생성자 실행
}
}

$static1 = & new hTest;
$static2 = & new hTest;
$static3 = & new hTestExt;
$static4 = & new hTestExt2;

$static1->STATIC->MEMBER1 .= "[hTest-MEMBER1]static1's STATIC\n";
$static2->STATIC->MEMBER1 .= "[hTest-MEMBER1]static2's STATIC\n";
$static3->STATIC->MEMBER1 .= "[hTestExt-MEMBER1]static3's STATIC\n";
$static4->STATIC->MEMBER1 .= "[hTestExt2-MEMBER1]static4's STATIC\n";

$static1->STATIC->MEMBER2 .= "[hTest-MEMBER2]static1's STATIC\n";
$static2->STATIC->MEMBER2 .= "[hTest-MEMBER2]static2's STATIC\n";
$static3->STATIC->MEMBER2 .= "[hTestExt-MEMBER2]static3's STATIC\n";
$static4->STATIC->MEMBER2 .= "[hTestExt2-MEMBER2]static4's STATIC\n";

//echo $static1->STATIC->MEMBER1;
echo $static2->STATIC->MEMBER1;
//echo $static3->STATIC->MEMBER1;
//echo $static4->STATIC->MEMBER1;

//echo $static1->STATIC->MEMBER2;
//echo $static2->STATIC->MEMBER2;
echo $static3->STATIC->MEMBER2;
//echo $static4->STATIC->MEMBER2;

?> [/code]
< 소스 코드(test.php3) >
[hTest-MEMBER1]static1's STATIC
[hTest-MEMBER1]static2's STATIC
[hTestExt-MEMBER1]static3's STATIC
[hTestExt2-MEMBER1]static4's STATIC
[hTest-MEMBER2]static1's STATIC
[hTest-MEMBER2]static2's STATIC
[hTestExt-MEMBER2]static3's STATIC
[hTestExt2-MEMBER2]static4's STATIC
< 실행결과 >
이 방법은 PHP4에서만 가능합니다. 이를 통해 객체지향 프로그래밍에서 요구하는 정적 데이터멤버를 별어려움 없이 흉내낼 수 있을 것입니다.

Posted by 방글24
phpclass/클래스활용2000. 6. 12. 14:54
정적 멤버함수
정적 멤버함수(C++) = 클래스 메소드(자바)
일반 멤버함수는 클래스만 선언한다고 해서 호출할 수 있는 것이 아니라 반드시 객체를 생성한 후에 객체를 통하여 호출되어야 합니다. 멤버 함수가 하는 일이 객체를 대상으로 수행되는 것이기 때문에 반드시 객체가 있어야 합니다. 반면 정적 멤버함수(static member function)는 객체가 없어도 호출할 수 있습니다. 정적 멤버함수는 특정 객체를 대상으로 수행되는 것이 아니고 주로 정적 데이터멤버(PHP에서는 정적 데이터멤버가 아직 지원되지 않고 있음)를 대상으로 수행하기 때문에 객체없이도 호출이 가능합니다.
정적 멤버함수는 그 클래스 자체에 전역적(클래스 스코프)이며 다른 클래스나 객체에 서로 사용될 수 있습니다. 그래서 정적 멤버함수는 그 클래스의 인스턴스가 있든 없든 상관없이 어느 곳에서나 사용될 수 있는 것입니다. 이러한 경우에는 정적 멤버함수를 정의하고 있는 클래스의 이름을 범위연산자 "::"와 연결되어 사용되어야 합니다.
클래스명::멤버함수
정적 멤버함수의 용도
객체를 통해서만 호출할 수 있는 일반 멤버함수와 달리 정적 멤버함수는 객체없이도 호출될 수 있습니다. 따라서 프로그램에서 객체를 생성하기 전에 반드시 실행하여야 하는 작업 또는 인스턴스를 모두 삭제한 다음에 반드시 실행하여야 하는 작업 등이 정적 멤버함수로 정의되는 것이 바람직합니다.
PHP에서의 정적 멤버함수의 한계
정적 멤버함수가 다루어야 할 가장 기본적인 요소(멤버)는 정적 데이터멤버입니다. 정적 데이터멤버 역시 정적 멤버함수와 마찬가지로 객체와 관계없이 클래스 스코프(사용범위)를 가지고 있기 때문에 정적 멤버함수에서 다룰 수 있는 유일한 데이터멤버입니다. 그러나 PHP에서는 아직 정적 데이터멤버에 대하여 제공하고 있지 않으므로 정적 멤버함수에서는 단지 전역변수와 지역변수만 다룰 수 있습니다. 클래스 내에서 전역변수를 사용한다는 것은 객체지향언어의 캡슐화하고는 거리가 멀고 지역변수는 특정 멤버함수만 사용할 수 있으니 모든 멤버함수가 공유하기는 어렵기 때문에 사용상 한계를 가지고 있습니다.
PHP4로 업그레이드하면서 정적 멤버함수를 지원하면서 왜 정적 데이터멤버를 빼버렸는지는 모르겠으나 그것은 개발자 맘(?)이고, 우리는 주어진 기능을 최대한 이용하여야 겠지요.

Posted by 방글24
phpclass/클래스활용2000. 6. 12. 14:53
소멸자란?
객체지향언어에서는 생성된 객체가 사라질 때 수행해야 할 일을 소멸자(destructor) 내에서 처리하도록 되어 있습니다. 클래스가 상속관계에 있을 때에 각 클래스에 있는 소멸자의 실행순서는 생성자와 반대로 동작하게 됩니다. 즉, 파생클래스의 소멸자가 먼저 실행된 다음에 부모클래스의 소멸자가 순서대로 실행됩니다.
PHP3에서의 소멸자
PHP3에서는 소멸자를 지원하지 않습니다. 따라서 객체를 제거할 때에 수행해야 할 함수가 있다면 이를 수행할 수 있는 함수를 아래와 같이 작성할 수 있습니다.
[code php;gutter:false] <?php

class test {
function destructor() {
// 여기에 객체를 제거할 때 수행해야할 기능을 추가
}
}

$obj = new test;
.
.
.
$obj->destructor();
unset($obj);
.
.
.

?> [/code]
unset() 함수에 의해 객체는 메모리에서 제거될 것입니다. 그러나 스크립트 종료 직전에는 unset() 함수를 사용할 필요는 없습니다. 스크립트의 실행이 종료되면 객체들도 자동적으로 제거됩니다.
PHP3에서의 소멸자 구현
객체 생성할 때 register_shutdown_function() 함수를 이용해 전역함수를 작성한 후 이 전역함수 내에서 스크립트가 종료될 때 수행될 최하위 파생클래스에 대한 소멸자를 실행하세요.
[code php;gutter:false] <?php

function __register_destructor() {
global $obj;
$obj->testext_destructor();
}

class test {
// 생성자
function test() {
// 여기에 객체를 생성할 때 수행해야할 기능을 추가
}

// 사용자 정의 소멸자
function test_destructor() {
// 여기에 객체를 제거할 때 수행해야할 기능을 추가
}
}

class testext extends test {
// 생성자
function testext() {
$this->test();
// 여기에 객체를 생성할 때 수행해야할 기능을 추가
}

// 사용자 정의 소멸자
function testext_destructor() {
// 여기에 객체를 제거할 때 수행해야할 기능을 추가
$this->test_destructor();
}
}

$obj = new testext;
register_shutdown_function("__register_destructor");
.
.
.

?> [/code]
클래스가 상속관계에 있을 때에 각 클래스에 있는 소멸자의 실행순서는 파생클래스의 소멸자가 먼저 실행된 다음에 부모클래스의 소멸자가 순서대로 실행된다는 사실에 주의하세요. 따라서 아래와 같이 현재 클래스의 소멸자에서 처리할 내용을 먼저 수행한 후에 부모클래스의 소멸자를 수행하도록 작성하여야 합니다.
[code php;gutter:false] function testext_destructor() {
// 여기에 객체를 제거할 때 수행해야할 기능을 추가
$this->test_destructor();
} [/code]
PHP4에서의 소멸자
PHP3와 마찬가지로 소멸자를 지원하지 않습니다.

Posted by 방글24
phpclass/클래스활용2000. 6. 12. 14:52
생성자란?
생성자(constructor)는 객체가 만들어질 때 자동으로 호출되며 객체를 초기화시키는 것이 주임무입니다. 객체를 초기화한다는 것은 주로 데이터멤버 초기화, 메모리 할당 등을 수행한다는 것을 의미하지요. 이런 일 외에도 프로그래머 필요에 따라 생성자를 실행하는 중에 멤버 함수 또는 외부함수를 호출하여 프로그램을 시작하기 전에 필요한 기능을 수행할 수도 있습니다. 예를 들면 데이터베이스 연동에 필요한 초기작업과 같은 것이 있고, 데이터베이스와 연동되는 세션기능을 하는 클래스가 있다면 앞 페이지에서 데이터베이스에 저장된 데이터를 데이터베이스에서 읽어온 후 데이터멤버를 초기화하는 기능도 할 수 있겠지요. 또한 쿠키 설정을 생성자에서 수행하는 것이 편리할 수도 있습니다. 이와 같이 프로그래머의 아이디어에 따라서는 더 다양한 활용이 가능하리라 봅니다.
PHP3에서의 생성자
PHP3 에서 구현된 생성자는 그 기능이 매우 제한적으로 이루어지고 있습니다. 여러 개의 클래스가 상속관계에 있을 때, 프로그래머가 마지막으로 정의한 생성자만 수행할 수 있으며, 다른 생성자는 수행되지 않습니다. 이는 스크립트 내에 생성자를 위한 공간이 하나만 확보되어 있기 때문입니다.
이런 이유로 PHP 홈페이지의 온라인 매뉴얼에도 생성자를 사용할 때는 아래와 같이 주의하여 사용하도록 하고 있습니다. 아래는 Manual: Chapter 13. Classes and Objects 문서 중 마지막 부분 발췌한 내용입니다.
......
Caution For derived classes, the constructor of the parent class is not automatically called when the derived class's constructor is called.
......
따라서 프로그래머가 각 클래스마다 생성자를 정의하더라도 생성자로는 상속되지 않으며, 단지 일반 멤버함수로 상속됩니다. 생성자라는 것이 본래 목적이 객체가 만들어질 때 자동으로 호출되며 객체를 초기화시키는 것이 주임무로 최상위 클래스(top class)의 생성자로부터 최하위 파생클래스의 생성자까지 순서대로 호출되어야 하는 특별한 멤버함수입니다. 따라서 생성자로 상속된다면 이러한 생성자로서의 기능을 다해야 함에도 불구하고 PHP3에서 객체 생성할 때 마지막으로 정의된 클래스의 생성자만을 호출하고 그 이상의 부모클래스의 생성자는 실행하지 않고 종료합니다.
[code php;gutter:false] <?php

class test {
//
// 부모클래스의 생성자
//
function test() {
echo("class test:test() 부모클래스 생성자\n");
}
}

class test2 extends test {
//
// 파생클래스의 생성자
//
function test2() {
echo("class test2:test2() 파생클래스 생성자\n");
}
}

$obj = new test2;

?> [/code]
위 예제의 실행결과는 아래와 같습니다.
class test2:test2() 파생클래스 생성자
즉, 객체 생성할 때 마지막으로 정의된 클래스의 생성자만을 호출하고 종료합니다.
PHP3에서의 생성자 체인 구현
위에서 살펴본 바와 같이 PHP에서는 마지막으로 정의된 생성자만 객체 생성할 때 호출되기 때문에 만약 부모클래스의 생성자를 연속적으로 실행하려면 파생클래스의 생성자 내부에서 부모클래스의 생성자를 호출하여야 합니다.
이것이 가능한 것은 생성자의 함수명이 각 클래스마다 다르기 때문에 부모클래스에 정의된 생성자는 나중에 정의된 파생클래스의 생성자에 의해 덮어 쓰이게 되는 것이 아니라 일반 멤버함수로 계속 존재하게 됩니다. 따라서 마지막으로 정의된 생성자로부터 부모클래스의 생성자를 멤버함수로 접근할 수 있습니다.
[code php;gutter:false] class Cart {
var $items; // Items in our shopping cart

function Cart () {
$this->add_item ("10", 1);
}
// Add $num articles of $artnr to the cart

function add_item ($artnr, $num) {
$this->items[$artnr] += $num;
}

// Take $num articles of $artnr out of the cart

function remove_item ($artnr, $num) {
if ($this->items[$artnr] > $num) {
$this->items[$artnr] -= $num;
return true;
} else {
return false;
}
}
}

class Auto_Cart extends Cart {
function Auto_Cart () {
$this->Cart ();
}
} [/code]
get_parent_class 함수를 이용하면 더 개선된 로직을 구성할 수 있습니다.
[code php;gutter:false] class Auto_Cart extends Cart {
function Auto_Cart () {
$parent = get_parent_class($this);
$this->$parent ();
}
} [/code]
이처럼 C++과 같은 다른 객체지향언어와 같이 최상위 클래스로부터 최하위 클래스까지 순차적으로 생성자를 수행하기 위해서는 모든 파생클래스 생성자 내부에서 부모클래스의 생성자를 호출해 주는 코드를 포함시켜주면 됩니다.
PHP4에서의 생성자
PHP4 에서도 PHP3와 같이 마지막으로 정의된 생성자만 실행된다는 점에서 같습니다. 그러나 마지막 정의되는 위치가 어디냐에 따라 실행결과가 전혀 달라질 수 있으니 주의하셔야 합니다. 이에 대한 자세한 내용을 "클래스사용법"의 "생성자" 부분을 참조바랍니다.

Posted by 방글24
phpclass/클래스활용2000. 6. 12. 14:51
함수 재정의란?
객체지향언어에서 말하는 함수 재정의(함수 오버라이딩;function overriding)는 부모클래스(base class)에서 정의되어 있는 멤버함수를 파생클래스(derived class)에서 자신에 맞는 멤버함수로 재정의 하여 부모클래스의 멤버함수를 무효화시키는 경우를 말합니다. 이를 위해서는 재정의 하고자 하는 부모클래스에 있는 함수의 함수명, 파라미터 수 및 데이터형을 동일하게 하여 파생클래스에 정의하면 됩니다.
PHP3에서의 함수 재정의
위에서 정의한 의미로 보면 PHP3에서는 함수 재정의라는 것이 특별히 정의되어 있지 않습니다. PHP3는 스크립트라는 특성 때문인지 모르겠으나 함수명만 같으면 파라미터 수 또는 데이터형에 관계없이 몇 개의 함수를 정의하던지 하나만 유효합니다. 같은 클래스 내에서는 아래쪽에 정의된 함수만 유효하며 두개 이상의 클래스가 상속 관계에 있을 때는 파생클래스에서 정의된 함수만 유효합니다. 즉 나중에 정의된 함수만 접근할 수 있습니다.
예를 들어보면,
첫째, 같은 클래스 내에 동일한 함수명으로 정의한 경우
[code php;gutter:false] <?php

class test {
//
// 멤버함수 a() case #1
//
function a() {
echo("class test:a() case #1\n");
}

//
// 멤버함수 a() case #2
//
function a($k) {
echo("class test:a($k) case #2\n");
}
}

$obj = new test;
$obj->a("파라미터");

?> [/code]
두 개의 멤버함수 a($k)와 a() 중 a($k)만 유효합니다. 즉 나중에 정의된 것만 호출할 수 있습니다. 따라서 객체를 생성할 때와 멤버함수를 호출할 때 위의 예와 같이 $obj->a("파라미터"); 라고 기술해야지 $obj->a();와 같이 기술하면 에러가 발생합니다. 위 예제의 실행결과는 아래와 같습니다.
class test:a(파라미터) case #2
위에서 정의한 것은 함수의 파라미터수가 다르기 때문에 C++과 같은 객체지향언어에서는 함수 오버로딩(overloading;중복정의)에 해당됩니다. 즉, a($k)와 a() 함수 둘 다 유효해야 하나, PHP에서는 마지막 정의 함수만 유효하게 됩니다. 마치 오버라이딩(재정의)된 것처럼...
둘째, 상속관계에 있는 부모와 파생클래스에 각각 동일한 함수명으로 정의한 경우
[code php;gutter:false] <?php

class test {
//
// 멤버함수 a() case #1
//
function a($k) {
echo("class test:a($k) case #1\n");
}
}

class test2 extends test {
//
// 멤버함수 a() case #2
//
function a($k) {
echo("class test2:a($k) case #2\n");
}
}

$obj = new test2;
$obj->a("파라미터");

?> [/code]
위 예제의 실행결과는 아래와 같습니다.
class test2:a(파라미터) case #2
즉, 동일한 이름으로 정의된 함수가 부모클래스와 파생클래스에 각각 정의하게 되면 나중에 나타나는 파생클래스에서 정의된 함수만 유효합니다.
PHP3에서의 함수 오버라이딩(재정의) 구현
PHP 에서는 파라미터 수 관계없이 함수명만 같으면 몇 개를 정의하더라도 마지막에 정의된 것만 유효하므로 특별히 함수 오버라이딩을 구현할 필요가 없습니다. 프로그래머가 알아서 파라미터 수를 같게 해서 정의하고 사용할 때 데이터형을 정확하게 맞춰주면 그것이 오버라이딩과 같은 효과를 얻을 수 있습니다. 문제는 오히려 함수 중복정의(오버로딩)가 안 된다는데 있습니다.
PHP4에서의 함수 재정의
PHP4에서는 재정의(?)되기 이전의 원래 메소드에 접근하기 위한 범위연산자가 제공되고 있습니다. 자세한 것은 "클래스사용법"의 범위연산자를 참조하세요.

Posted by 방글24