phpclass/객체모델2005. 10. 11. 12:21
written: Oct 18 2005
상수
상수(constant)라는 것은 프로그램에서 한번 값이 결정되면 다시는 새로운 값으로 변경될 수 없는 객체입니다. 언어마다 상수의 분류가 다소 다르기는 합니다만 대체적으로 숫자형, 문자형, 문자열 상수로 구분되며 자바에서는 부울린형이 추가되어 있습니다. 참고로 자바에서는 상수를 리터럴(literal)이라고 부릅니다.
< 상수의 분류 >
대분류 소분류 사용예
숫자형 정수 1, 100, 2005, 0777, 0xFF, ...
실수 1.2, 100.0, 3.1415927, ...
지수 0.12e-2, 10e45, 0.36E-3, ...
문자형 영문자 소문자 'a' - 'z', 대문자 'A' - 'Z'
숫자형문자 '1'  - ' 9'
특수문자 '#', '$', '?', newline과 같은 escope code, ...
부울린형 예약어 true, false
문자열형 "Hello world.", ...
상수를 변수처럼 사용하는 방법
각 언어마다 상수를 변수처럼 이름을 가진 상수로 사용할 수 있도록 해줍니다. 이 방법은 언어마다, 그리고 상수가 정의된 위치에 따라 다를 수 있기때문에 각 언어별(PHP, C++, 자바)로 상수이름을 어떻게 정의하여 사용할 수 있는지 살펴보겠습니다.
PHP에서는 5.0부터 클래스에서 정의되는 상수를 제공합니다. 이 상수를 클래스 상수라고 하며 기존의 전역영역에서 사용하던 전역상수와 구별하여 사용할 수 있습니다.
PHP에서 전역상수를 정의하기 위해서는 define 함수를 이용합니다.
[code php;gutter:false] <?php define("PI", 3.1415927); echo PI; ?> [/code]
C++에서는 아래와 같은 방법으로 상수의 이름을 사용하도록 해줍니다.
[code c;gutter:false] #define PI 3.1415927 [/code]
위와 같은 C++에서의 방법은 PHP의 define() 함수에 의한 방법과는 그 구현방법이 다릅니다. C++에서의 #define은 프리프로세서(preprocessor)로 매크로 기능을 이용하는 방법으로 컴파일하기 전에 상수이름이 해당 상수로 모두 대치됩니다.
PHP의 define() 함수에 의해 정의된 상수는 하나의 기억장소에 저장되나 그 값이 변수처럼 새로운 값으로 치환되지 못하도록 합니다.
아래와 같이 C++에서의 또 다른 상수이름을 지정할 수 있는 방법인 const 키워드를 이용하는 방법이 있으며 이 방법의 의해 정의된 상수이름은 PHP의 define() 함수에 의해 정의된 함수처럼 하나의 기억장소를 할당받으며 그 값을 변경할 수 없습니다.
[code c;gutter:false] const float pi = 3.1415927; [/code]
PHP5에서 제공되는 클래스 상수가 위와 유사하게 const 키워드를 이용하여 정의합니다.
[code php;gutter:false] const pi = 3.1415927; [/code]
PHP에서는 float와 같은 자료형을 지정하지 않는다는 것을 감안하면 C++ 표현 방식과 같다는 것을 알 수 있습니다.
참고로 자바에서는 #define, const 대신에 final 키워드를 사용하여 상수(리터럴) 이름을 지정할 수 있습니다.
[code java;gutter:false] final float pi = 3.1415927; [/code]
클래스 상수
클래스 상수는 클래스 단위로 설정할 수 있는 상수로 아래와 같이 const 키워드를 사용하여 클래스 상수를 정의하며 전역 상수와 마찬가지로 변수를 나타내는 $ 문자를 붙이지 않습니다.
const 클래스상수명 = '상수값';
클래스 상수는 클래스 안에서 사용되는 키워드 $this뿐만 아니라 생성된 인스턴스를 가지고는 접근할 수 없습니다. 따라서 클래스 상수를 사용하기 위해서는 아래와 같이 self, parent 키워드 또는 클래스명을 통해 접근해야 합니다.
[code php;gutter:false] <?php class super_class { const constant = 'super_class::constant value'; function show_constant() { print self::constant . "\n"; } } class sub_class extends super_class { const constant = 'sub_class::constant value'; function show_constant() { print parent::constant . "\n"; print self::constant . "\n"; } } /** * This will print * super_class::constant value */ print super_class::constant . "\n"; /** * This will print * sub_class::constant value */ print sub_class::constant . "\n"; $obj = new sub_class; /** * This will print * super_class::constant value * sub_class::constant value */ $obj->show_constant(); /** * This will print * super_class::constant value * sub_class::constant value */ sub_class::show_constant(); /** * This will print * super_class::constant value */ super_class::show_constant(); /** * echo $obj::constant; is not allowed */ ?> [/code]
< 클래스 상수 사용하기 >
클래스 상수는 항상 public 가시범위(visibility)를 가지고 있기 때문에 const 키워드 앞에는 public 접근 제한자를 포함하여 어떠한 접근제한자도 지정해서는 안됩니다.

Posted by 방글24
phpclass/객체모델2005. 10. 11. 12:17
written: Oct 12 2005
추상클래스는 객체가 가지는 특성들을 추상화시켜 놓았을 뿐 아직 인스턴스화될 수 없는 클래스입니다. "상단메뉴 >> 클래스&객체 > 추상클래스"를 참조하셔서 먼저 추상클래스가 무엇인지를 이해하시기 바랍니다.
추상클래스(abstract class)
[code php;gutter:false] <?php /** * 동물(animal) 추상클래스 */ abstract class animal { abstract protected function is_body_size(); public function display($kind) { print $kind . '의 몸집은 ' . $this->is_body_size() . ".\n"; } } /** * 사자(lion) 클래스 */ class lion extends animal { protected function is_body_size() { return '크다'; } } /** * 거북이(turtle) 클래스 */ class turtle extends animal { protected function is_body_size() { return '작다'; } } $obj = new lion; $obj->display('사자'); $obj = new turtle; $obj->display('거북이'); ?> [/code]
위의 예제의 출력결과는 아래와 같습니다.
사자의 몸집은 크다.
거북이의 몸집은 작다.
lion(사자)나 turtle(거북이)라는 것이 실제로 존재하는 것이라면 animal(동물)이라는 것은 사자, 거북이 등의 특성을 가진 생물을 모두 지칭하는 추상적인 용어일 것입니다. 위의 예에서 보다시피 각 동물마다 몸집크기는 제각각일 것이고 따라서 추상클래스에서는 몸집크기를 알아내는 메쏘드 is_body_size()를 실제적으로 구현할 수 없습니다.
이와 같이 추상클래스라는 것이 실제로 객체로 생성할 수 있도록 구현된 것이 아니라 구현하고자 하는 객체들이 가지는 특성들을 추상화시켜 놓은 것입니다. 따라서 각 객체가 가지는 구체적인 특성들은 하위클래스에서 재정의(overriding)를 통해 구현해 주어야 합니다.
추상클래스라고해서 모든 멤버가 추상적이어야 하는 것은 아닙니다. 때에 따라서는 추상클래스에서도 일반클래스와 마찬가지로 실제로 구현된 멤버를 가질 수 있습니다. 동물(animal)이라는 추상적인 개념에서도 "움직인다"와 같이 실제로 구현될 수 있는 특성을 포함할 수 있는 것과 같다고 볼 수 있습니다.
[code php;gutter:false] <?php abstract class animal { abstract protected function is_body_size(); protected $action = '움직인다'; public function display($kind, $speed) { print $kind . '의 몸집은 ' . $this->is_body_size() . ".\n"; print $kind . '는 ' . $speed . ' ' . $this->action . ".\n"; } } class lion extends animal { protected function is_body_size() { return '크다'; } } class turtle extends animal { protected function is_body_size() { return '작다'; } } $obj = new lion; $obj->display('사자', '빠르게'); $obj = new turtle; $obj->display('거북이', '느리게'); ?> [/code]
위의 예제의 출력결과는 아래와 같습니다.
사자의 몸집은 크다.
사자는 빠르게 움직인다.
거북이의 몸집은 작다.
거북이는 느리게 움직인다.
위의 예에서 보시다시피 추상클래스라는 것이 그 자체로는 실제로 할 수 있는 일이 없습니다. 그러나 상속과 재정의를 통해서 매우 쓸모있는 것으로 바꿀 수 있습니다.
추상메쏘드(abstract method)
추상메쏘드는 아래의 예와 같이 함수의 몸체가 없고 단지 프로토타입만 선언해주는 메쏘드입니다.
[code php;gutter:false] abstract protected function is_body_size(); [/code]
이러한 추상메쏘드는 추상메쏘드를 포함하고 있는 클래스를 상속한 하위클래스에서 그 몸체를 실제적으로 구현해 주어야  일반 클래스처럼 객체를 생성하여 사용할 수 있습니다.
[code php;gutter:true] <?php abstract class animal { abstract protected function is_body_size(); protected static $kind = '동물'; public function display() { print self::$kind . "의 몸집은 그 종류에 따라 다릅니다.\n"; } } $obj = new animal; /* Fatal error 발생 */ $obj->display(); ?> [/code]
위와같이 추상클래스로 객체를 생성하려고 시도하면 아래와 같이 11번행에서 Fatal error가 나타납니다.
Fatal error: Cannot instantiate abstract class animal
추상메쏘드는 추상클래스 안에서만 존재할 수 있기때문에 클래스 안에 하나 이상의 추상메쏘드가 포함되어 있으면 그 클래스는 반드시 추상클래스로 지정해 주어야 합니다.
[code php;gutter:true] <?php class animal { abstract protected function is_body_size(); } /* Fatal error 발생 */ ?> [/code]
위와같이 클래스를 abstract로 지정하지 않고 추상메쏘드를 포함시키면 아래와 같이 4번행에서 Fatal error가 나타납니다.
Fatal error: Class animal contains 1 abstract methods and must therefore be declared abstract (animal::is_body_size)
추상메쏘드의 가시범위(visibility)
추상메쏘드는 하위클래스에서 반드시 구현해주어야 하기 때문에 protected 또는 public으로 지정해 주어야 하며 private로 지정할 수 없습니다.
< 추상메쏘드의 PPP 지정 및 상속 >
접근제한자 private protected public

추상메쏘드에 지정할 수 있는

접근제한자

지정할 수 없음 O O

하위클래스의 재정의된 메쏘드에서

지정할 수 있는 접근제한자

N/A

protected

public

public
 (NA:Non Applicable;해당없음).....
추상클래스의 상속
상위추상클래스를 상속받은 하위클래스에서는 상위추상클래스의 추상메쏘드를 모두 구현할 수도 있고, 새로운 추상메쏘드를 추가할 수도 있고, 상위추상클래스에 있는 일부 추상메쏘드를 구현하지 않고 계속 남겨둘 수도 있습니다. 하위클래스에 일부 추상메쏘드가 구현되지 않고 계속 남아있는 경우에 이 하위클래스도 역시 추상클래스이므로 반드시 abstract로 지정해 주어야 하며 역시 객체를 생성할 수 없습니다.
[code php;gutter:true] <?php abstract class animal { abstract protected function is_body_size(); abstract protected function is_speed(); public function display($kind) { print $kind . '의 몸집은 ' . $this->is_body_size() . ".\n"; } } class lion extends animal { protected function is_body_size() { return '크다'; } } $obj = new lion; /* Fatal error 발생 */ $obj->display('사자'); ?> [/code]
위와같이 상위추상클래스에 있는 추상메쏘드를 모두 구현하지 않은 하위클래스를 가지고 객체를 생성하려고 시도하면 아래와 같이 17번행에서 Fatal error가 나타납니다.
Fatal error: Cannot instantiate abstract class animal
위와 같은 경우에 사자(lion) 클래스를 아래와 같이 추상클래스로 수정해야 하며 상속된 하위추상클래스를 상속한 그 하위클래스에서 나머지 추상메쏘드를 모두 구현하고 난 다음에 객체를 생성할 수 있습니다.
[code php;gutter:false] <?php abstract class lion extends animal { protected function is_body_size() { return '크다'; } } class concreat_lion extends lion { protected function is_speed() { return '빠르다'; } } $obj = new concreat_lion; $obj->display('사자'); ?> [/code]

Posted by 방글24
phpclass/객체모델2005. 10. 11. 12:13
written: Oct 06 2005
last modified: Oct 11 2005
 
앞 문서들에서 접근제한자를 이용하여 가시범위(visibility) 지정하는 방법에 대하여 알아보았습니다. 이번 문서에서는 범위 지정 연산자(scope resolution operator;범위지정자)를 이용하여 유효범위(scope)를 지정하는 방법에 대하여 살펴보겠습니다.
유효범위(scope)
유효범위라는 것은 하나의 멤버를 기준으로 그 멤버에 접근할 수 있는 프로그램 영역을 나타내는 것으로 만일 프로그램의 모든 곳에서 접근할 수 있는 멤버라면 그 멤버의 유효범위는 프로그램 전체가 됩니다. 모든 멤버(변수, 함수, 상수)의 유효범위(scope)는 그 멤버가 정의되어 있는 프로그램의 위치에 따라 결정됩니다.
zend 1.0과 2.0의 유효범위에 관한 자세한 내용은  "상단메뉴 >> 클래스&객체 > Zend엔진 2.0 설계초안 > 이름공간(namespace)"를 참조바랍니다.
위 문서에 따르면 Zend 엔진에서는 아래와 같이 3가지의 유효범위를 제공하는 것으로 보입니다.
  • 전역 스코프(golbal scope)
  • 함수 스코프(function scope)
  • 클래스 스코프(class scope)
본 문서에서는 유효범위를 구분할 때에는 유효범위라는 용어보다는 스코프라는 용어를 직접 사용하여 가능한한 용어 사용상 혼동이 없도록 하겠습니다.
위에서 구분된 함수 스코프(function scope)라는 용어를 C++과 같은 언어에서는 지역 스코프(local scope)라고 부르고 있으며 함수 스코프는 다른 뜻으로 사용하고 있으니 양쪽 언어를 넘나드는 분들은 혼동없기를 바랍니다.
참고로 C++에서는 지역 스코프를 아래와 같이 설명하고 있습니다.
함수 또는 함수에 있는 어떤 블록(block) 안에서 정의되어 있는 모든 변수들은 지역 스코프를 가진다.
PHP에서는 블록 안에서만 사용할 수 있는 변수를 허용하지 않고 다만 함수 내에서 사용할 수 있는 변수를 허용하고 있습니다.
클래스 스코프(class scope)
Zend 엔진 2.0 알파2가 발표되면서 클래스 스코프와 관련하여 큰 변화는 중첩클래스(nested class;내부클래스)를 허용한다는 것과 import 문의 도입이었을 것입니다만 PHP5.0.0b1 이후 현재버전(5.0.4)에서는 둘 다 삭제되어 있습니다. 클래스 스코프에 포함될 수 있는 멤버를 보면 아래와 같습니다.
< 클래스 스코프 (o:포함허용, x:포함불가) >

\

Zend 엔진 버전

------------------

 멤버

\

1.0 2.0 알파2

2.0

상수

X

O

O

변수

O

O

O

함수

O

O

O

클래스

X

O

X

범위 지정 연산자(::)
앞에서 모든 멤버는 그 멤버가 정의된 프로그램 위치에 따라 그 멤버의 유효범위가 결정된다고 하였습니다. 그런데 때로는 자신이 속한 유효범위를 명시적으로 지정하여 사용할 수도 있습니다. 이러한 목적으로 범위 지정 연산자(scope resolution operator;범위지정자)를 사용합니다.
범위 지정 연산자를 이용하면 부모클래스 내에 있는 재정의되기 전의 멤버 또는 아직 인스턴스를 갖고 있지 않는 클래스 멤버에 접근할 수 있습니다.
클래스 밖에서 클래스 멤버 접근하기
클래스 밖에서 클래스 멤버에 접근하기 위해서는 "클래스명::멤버"와 같이 지정합니다.
상수(constant)
[code php;gutter:false] <?php class my_class { const MY_CONST = 'A constant value.'; } print my_class::MY_CONST . "\n"; ?> [/code]
< 상수에 접근하기 >
위 소스를 실행하면 "A constant value.\n"를 출력할 것입니다.
변수(variable)
[code php;gutter:false] <?php class my_class { public static $public_var = "my_class::public_var"; } print my_class::$public_var . "\n"; ?> [/code]
< 변수에 접근하기 >
위 소스를 실행하면 "my_class::public_var\n"를 출력할 것입니다.
함수(function)
[code php;gutter:false] <?php class my_class { public function my_function() { print "my_class::my_function()\n"; } } class my_class2 extends my_class { public function my_function() { my_class::my_function(); print "my_class2::my_function()\n"; } } /** * This will print * my_class::my_function() */ my_class::my_function(); /** * This will print * my_class::my_function() * my_class2::my_function() */ ?> [/code]
< 함수에 접근하기 >
클래스 안에서 클래스 멤버 접근하기
클래스 안에서 클래스 멤버에 접근할 때는  "클래스명::멤버"와 같이 지정할 수도 있으나 PHP4부터 제공되기 시작한 self와 parent 접근자를 이용하여 자신의 클래스나 상위 클래스의 멤버에 접근하는 것이 더 바람직합니다.
상수(constant)
[code php;gutter:false] <?php class my_class { const MY_CONST = "my_class::MY_CONST\n"; protected function my_function() { print self::MY_CONST; } } class my_class2 extends my_class { const MY_CONST = "my_class2::MY_CONST\n"; public function my_function() { print parent::MY_CONST; print self::MY_CONST; } } /** * This will print * my_class::MY_CONST */ my_class::my_function(); /** * This will print * my_class::MY_CONST * my_class2::MY_CONST */ my_class2::my_function(); ?> [/code]
< 상수에 접근하기 >
변수(variable)
[code php;gutter:false] <?php class my_class { public static $protected_var1 = "my_class::protected_var1\n"; public function my_function() { print self::$protected_var1; } } class my_class2 extends my_class { protected static $protected_var2 = "my_class2::protected_var2\n"; public function my_function() { print parent::$protected_var1; print self::$protected_var2; } } /** * This will print * my_class::protected_var1 */ my_class::my_function(); /** * This will print * my_class::protected_var1 * my_class2::protected_var2 */ my_class2::my_function(); ?> [/code]
< 변수에 접근하기 >
(에러수정) 예제가 잘못 코딩되어 에러가 발생하여 예제를 수정하였습니다.
함수(function)
[code php;gutter:false] <?php class my_class { protected function my_function() { print "my_class::my_function()\n"; } } class my_class2 extends my_class { protected function my_function() { print "my_class2::my_function()\n"; } public function public_func() { print parent::my_function(); print self::my_function(); } } my_class2::public_func(); ?> [/code]
< 함수에 접근하기 >
위 소스를 실행하면 아래와 같은 결과를 얻을 수 있습니다.
my_class's my_function()
my_class2's my_function()
심볼테이블
"상단메뉴 >> 클래스&객체 > Zend엔진 2.0 설계초안 > 이름공간(namespace)"를 보게되면 Zend엔진 각 버전별로 클래스의 심볼(상수명, 변수명, 함수명, 클래스명 등)에 대한 기본적인 유효범위가 상이합니다.
[code php;gutter:true] <?php function bar() { print "global's bar()\n"; } class my_class { function my_function() { bar(); } function bar() { print "myclass::bar()\n"; } } ?> [/code]
< 함수의 유효범위 >
위의 예에서 8번행의 bar()가 실행되었을 때 Zend 엔진 1.0에서는 전역 스코프(global scope)를 가지게 되어 전역함수 bar()를 호출하게 되며 결과는 "global's bar()\n"를 출력할 것입니다. 그러나 Zend 엔진 2.0 알파2에서는 8번행의 bar()가 실행되었을 때 bar() 문이 클래스 스코프(class scope)를 가지게 되어 클래스 메쏘드인 bar()를 호출하게 되며 결과는 "myclass::bar()\n"를 출력할 것입니다.
그런데 PHP5.0이 정식으로 발표되면서 포함된 Zend 엔진 2.0에서는 원래대로 클래스 스코프가 아니라 전역 스코프를 가지도록 수정되었습니다.
< 8번행 bar()문의 유효범위 >

\

Zend 엔진 버전

------------------

 유효범위

\

1.0 2.0 알파2

2.0

전역 스코프

O

X

O

클래스 스코프

X

O

X

main 접근자
Zend 엔진 2.0 알파2에서 제공되던 범위 접근자인 main이 PHP5.0.0b1이 발표되면서 삭제되었습니다. 그 이유는 앞 항목인 "심볼테이블"에서 살펴보았지만  bar()문을 실행하였을 때 Zend 엔진 2.0 알파2에서는 클래스 my_class에 정의된 bar() 메쏘드를 호출하게 됩니다. 그러면 Zend 엔진 2.0 알파2에서 전역함수 bar() 함수를 호출하려면 어떻게 해야 하나요? 이럴 때를 위하여 제공하였던 것이 main 접근자입니다. main 접근자로 임의 지정된 멤버는 현재 위치에 관계없이 전역영역에 있는 멤버를 호출하도록 해줍니다.
main::bar();
PHP5.0.0b1 이후에 포함된 Zend 엔진 2.0에서는 bar()문을 실행하였을 때 Zend 엔진 1.0과 같이 클래스 메쏘드가 아닌 전역함수를 호출하도록 변경되었기 때문에 main 접근자가 필요없어졌습니다. 이러한 이유로 Zend 엔진 2.0에서는 main 접근자가 삭제되었습니다.

Posted by 방글24
phpclass/객체모델2005. 10. 11. 12:12
written: Sep 30 2005
last modified: Oct 11 2005
public 멤버
public 멤버는 프로그램의 어느 곳에서나 접근할 수 있습니다. 접근하는 곳이 전역영역일 수도 있고 다른 클래스의 멤버가 될 수도 있을 것입니다.
PHP4에서는 PPP 접근제한자를 허용하지 않았으며 변수는 var로, 메쏘드는 function으로만 선언할 수 있었습니다. 이렇게 작성된 멤버는 무조건 public 특성을 가지게 됩니다. PHP5에서도 var로 선언된 변수는 public 변수와 같으며, function 앞에 명시적으로 접근제한자를 붙이지 않으면 public 메쏘드로 처리합니다.

Posted by 방글24
phpclass/객체모델2005. 10. 11. 12:11
written: Sep 30 2005
last modified: Oct 11 2005
protected 멤버
protected 멤버는 해당 클래스 멤버뿐만 아니라 클래스를 상속받은 하위클래스에서도 상위클래스의 protected 멤버에 접근할 수 있습니다.
protected로 선언된 멤버의 경우에 C++이냐 자바냐에 따라 그 의미가 약간씩 다르기도 하고 추가되는 개념도 있습니다. 가장 큰 차이점은 C++에서는 바로 아래에 있는 하위 클래스에서만 접근할 수 있는 반면에 자바에서는 패키지라는 개념이 도입되어 패키지 안에 있는 어떤 클래스도 접근할 수 있게 해 줍니다. PHP5에서는 해당 클래스로부터 상속된 모든 하위클래스에서 접근할 수 있습니다.
해당 클래스에서는 protected 선언하나 private 멤버로 선언하나 그 동작이 동일합니다. 또한 다른 클래스나 전역영역에서 접근할 수 없다는 것도 동일합니다. 해당 클래스로부터 상속받은 하위클래스에서만 차이가 납니다. 상위클래스에서 private로 선언된 멤버는 접근할 수 없으나 protected로 선언된 멤버는 하위클래스에 상속되어 자유로이 접근할 수 있습니다.
[code php;gutter:false] <?php class my_class { protected $protected1 = "my_class::protected1!\n"; protected $protected2 = "my_class::protected2!\n"; protected function my_protected1() { return "my_class::my_protected1()!\n"; } protected function my_protected2() { return "my_class::my_protected2()!\n"; } function foo() { print "my_class::foo() " . $this->protected1; print "my_class::foo() " . $this->protected2; print "my_class::foo() " . $this->my_protected1(); print "my_class::foo() " . $this->my_protected2(); } } class my_class2 extends my_class { protected $protected1 = "my_class2::protected1!\n"; protected function my_protected1() { return "my_class2::my_protected1()!\n"; } function foo2() { print "my_class::foo2() " . $this->protected1; print "my_class::foo2() " . $this->protected2; print "my_class::foo2() " . $this->my_protected1(); print "my_class::foo2() " . $this->my_protected2(); } } $obj2 = new my_class2; /** * Will output * "my_class::foo2() my_class2::protected1!" * "my_class::foo2() my_class::protected2!" * "my_class::foo2() my_class2::my_protected1()!" * "my_class::foo2() my_class::my_protected2()!" */ $obj2->foo2(); ?> [/code]
< protected로 지정된 멤버의 동작 >

Posted by 방글24
phpclass/객체모델2005. 10. 11. 12:10
written: Sep 30 2005
last modified: Oct 11 2005
private 멤버
private 멤버는 해당 클래스내에서만 접근할 수 있습니다. 전역영역 및 다른 클래스는 물론이고 해당 클래스를 상속받은 하위클래스에서 조차 접근할 수 없는 가장 제한적인 방법입니다.
private 변수
[code php;gutter:true] class my_class { private $private = "my_class::private!\n; function foo() { print "my_class::foo() " . $this->private; } } $obj = new my_class; /** * Fatal error: Cannot access private property my_class::$private */ print $obj->private; $obj->foo(); [/code]
< private로 지정된 변수의 동작 >
14번행을 실행하면 아래와 같은 에러를 보게 됩니다.
Fatal error: Cannot access private property my_class::$private in xxx.php on line 14
private로 선언된 변수 $private는 전역 영역에서 접근할 수 없다는 것을 보여주는 것입니다. 반면에 16번행을 실행할 때는 별 탈(?)없이 잘 실행되지요. 클래스 my_class에 선언된 메쏘드 foo() 내에서는 같은 클래스에 선언된 private 변수 $private를 접근하는 데 아무런 문제가 없다는 것을 나타냅니다. 따라서 16번행을 실행하면 private 변수 $private의 값인 "my_class::private!\n이 정상적으로 출력됩니다.
다음에는 클래스 my_class를 상속한 하위클래스에서는 어떤 반응을 보이는지 살펴보겠습니다.
[code php;gutter:true] class my_class2 extends my_class { private $private = "my_class2::private!\n; function foo2() { print "my_class::foo2() " . $this->private; } } $obj2 = new my_class2; /** * Fatal error: Cannot access private property my_class2::$private */ print $obj2->private; $obj2->foo2(); [/code]
< 하위클래스에서 private로 지정된 변수의 동작 >
클래스 my_class에서 private로 선언된 $private를 하위클래스 my_class2에서 같은 변수명을 가지고 private로 선언해 보았습니다. 14번행을 실행하면 역시 아래와 같은 에러를 보게 됩니다.
Fatal error: Cannot access private property my_class2::$private in xxx.php on line 14
이전 에러메시지와 비교해 볼 때 달라진 점은 my_class::$private 대신에 my_class2::$private에 접근할 수 없다는 것입니다.. 만약에 하위클래스 my_class2에서 2번행을 삭제한다면 어떻게 될까요. 이 때는 아래와 같이 Notice 에러를 만나게 될 것입니다.
Notice: Undefined property: my_class2::$private in xxx.php on line 14
에러메시지를 보면 클래스 상위클래스인 my_class에 선언된 $private가 하위클래스로 전혀 상속되지 않으므로 객체 $obj2를 통해 접근한 $private는 처음 만나는 새로운 변수로 처리하고 있다는 것을 알 수 있습니다.
16번행 "$obj2->foo2()"를 실행할 때는 역시 문제없이 잘 실행됩니다. 하위클래스 my_class2에 선언된 메쏘드 foo2() 내에서는 같은 클래스에 선언된 private 변수 $private를 접근하는 데 아무런 문제가 없었다는 것을 알 수 있습니다. 따라서 16번행을 실행하면 메쏘드 foo2()를 통해(5번행) 하위클래스 my_class2에서 선언한 private 변수 $private의 값인 "my_class2::private!\n이 정상적으로 출력됩니다.
private 메쏘드
아래의 예제는 private로 선언된 메쏘드가 해당 클래스와 그 하위 클래스에서 어떻게 동작하는가를 알아보기 위해 작성된 것입니다. 각 행을 실행하면서 발생되는 에러메시지에 대하여는 그 행 바로 위에 주석으로 기술하였으니 참조바랍니다.
[code php;gutter:true] class my_class { private $private1 = "my_class::private1!\n; private $private2 = "my_class::private2!\n; private function my_private1() { return "my_class::my_private1()!\n; } private function my_private2() { return "my_class::my_private2()!\n; } function foo() { print "my_class::foo() " . $this->my_private1(); print "my_class::foo() " . $this->my_private2(); } } $obj = new my_class; /** * Fatal error: Call to private method my_class::my_private1() */ print $obj->my_private1(); $obj->foo(); class my_class2 extends my_class { private $private1 = "my_class2::private1!\n; private function my_private1() { return "my_class2::my_private1()!\n; } function foo2() { print "my_class::foo2() " . $this->my_private1(); /** * Fatal error: Call to private method my_class::my_private2() * from context 'my_class2' */ print "my_class::foo2() " . $this->my_private2(); } } $obj2 = new my_class2; /** * Fatal error: Call to private method my_class2::my_private1() */ print $obj2->my_private1(); /** * Fatal error: Call to private method my_class::my_private2() */ print $obj2->my_private2(); $obj2->foo2(); [/code]
< private로 지정된 메쏘드의 동작 >
42번행과 56번행을 실행하면 아래와 같은 에러메시지를 보게 됩니다.
Fatal error: Call to private method my_class::my_private2() ...
에러메시지를 보면 하위클래스 my_class2로 부터 생성된 객체 $obj2를 통해 my_private2()에 접근을 시도하면 이 메쏘드가 my_class2에는 존재하지 않고, 그 상위클래스에 private로 선언된 메쏘드임을 알 수 있습니다.
위의 에러메시지는 아래와 같이 보여주는 것이 PPP 접근제한자의 개념상 더 좋지 않을까 생각됩니다.
Fatal error: Call to undefined method my_class2::my_private2() in xxx.php on line xx
private 변수 항목에서 살펴보았듯이 이는 상위클래스에서 private로 선언되고 그 하위클래스에서는 선언되지 않은 변수를 하위클래스를 통해 접근할 때 아래와 같은 에러메시지를 보여주는 것과 비교하면 이해가 쉬울 것입니다.
Notice: Undefined property: my_class2::$private in xxxxxxxx.php on line 14

Posted by 방글24
phpclass/객체모델2005. 10. 11. 12:07
written: Sep 30 2005
last modified: Oct 11 2005
PPP 접근제한자(Private/Protected/Public access modifier)
C++ 또는 자바와 같은 프로그래밍 언어에는 멤버에 대한 접근 권한(access right)을 지정하는 private, protected, public라는 접근제한자(access modifier;접근지정자, 접근변경자, 접근수정자)가 있습니다. 여러분이 작성하고자 하는 코드를 더 잘 캡슐화(encapsulation)하기 위하여 접근제한자를 통해 멤버에 대한 접근을 제어하는 것입니다.
PHP에서도 버전 5.0부터 PPP 접근제한자를 이용할 수 있게 되어 객체지향 프로그램으로써 한 발 더 다가설 수 있게 되었습니다.
private : 해당 클래스 내에서만 접근할 수 있으며 하위클래스 또는 다른 클래스에서는 접근할 수 없다.
protected : 해당 클래스 및 클래스를 상속받은 하위클래스에서만 접근할 수 있다.
public : 모든 프로그램 영역에서 접근할 수 있다.
아래의 표는 각각의 접근제한자들이 각 프로그램 영역에서의 가시범위에 어떻게 포함되는지를 보여줍니다.
< 각 프로그램영역의 가시범위 >

\

가시범위

----------------

 프로그램영역

\

private

protected

public

동일클래스

O

O

O

하위클래스

X

O

O

다른클래스

X

X

O

전역영역

X

X

O

멤버의 PPP 보호 및 상속
(추가 2005.10.11)
하위클래스에서 상위클래스의 멤버를 재정의할 때는 원래 멤버에 지정된 PPP 접근제한자와 동일하거나 더 public하게 만들어야 합니다. 상위클래스에서보다 더 private한 멤버는 만들 수 없습니다.
  • 상위클래스에서 public로 지정된 멤버는 모든 하위클래스에서도 public 멤버로 지정하여야 합니다.
  • 상위클래스에서 protected로 지정된 멤버는 하위클래스에서 protected 또는 public 멤버로 지정하여야 합니다.
  • 상위클래스에서 private로 지정된 멤버는 상속되지 않으므로 하위클래스에서 동일한 이름의 멤버를 지정하더라도 상위클래스의 멤버와는 전혀 다른 새로운 멤버이므로 PPP 지정에 제한이 없습니다.
< 멤버의 PPP 보호 및 상속 >
상위클래스에서 지정된 접근제한자 private protected public

하위클래스에서 지정할 수 있는

접근제한자

상속안됨

protected

public

public

접근제한자와 관련된 코딩지침
  • 변수는 private로 선언하여 외부에서 접근할 수 없도록 하며, private 변수에 대한 작업이 필요하면 이들에 접근할 수 있는 메쏘드를 작성합니다.
  • 메쏘드도 외부에서 접근할 필요가 없다고 판단되면 private로 선언합니다. 즉, public 메쏘드를 최소화할 수 있도록 클래스를 설계합니다.
캡슐화(encapsulation)와 정보은닉(information hiding)
클래스에는 많은 변수와 메쏘드가 존재합니다만 이들 모두가 외부에서 접근할 필요가 있는 것은 아닙니다.  외부에서 접근해야 하는 메쏘드(이를 accessor method라 함)만을 public로 지정해주며, 나머지 모든 멤버는 private로 지정하여 클래스 내부 동작을 숨기게 됩니다. 이와 같이 내부 동작을 숨기는 것을 정보은닉(information hiding)이라 하며 이와같이 내부의 세부동작을 외부로부터 숨기므로 클래스를 사용하는 외부의 동작과 관계없이 클래스 내부 동작을 쉽게 변화시킬 수 있습니다.
클래스를 설계할 때는 외부에서 접근할 수 있는 멤버와 클래스 내부에서만 접근할 수 있는 멤버를 구분하여 클래스 내부에서 수행되는 부분을 감추게 되는데 이러한 작업을 캡슐화(encapsulation)라고 합니다. 캡슐화는 객체의 내부 동작을 숨기며, 객체가 정의한 인터페이스를 통해서만 접근할 수 있도록 하는 것입니다.
PPP 접근제한자를 이용하여 클래스 멤버의 가시범위를 적절히 제한함으로 정보은닉을 통해 클래스를 캡슐화하여 객체간의 상호의존성을 줄일 수 있으며 코드의 유지관리와 재사용을 높일 수 있습니다.

Posted by 방글24
phpclass/객체모델2005. 10. 11. 12:03
written: Sep 30 2005
last modified: Oct 11 2005
유효범위(scope)와 가시범위(visibility)
"www.php.net >> online document > Classes and Objects(PHP5)"를 보면 "Visibility"라는 항목에 PPP 접근제한자(Private/Protected/Public access modifier)를 설명하고 있습니다. 그래서 우선 "visibility"라는 용어부터 이해하고 넘어가도록 하겠습니다.
거의 모든 국내서적에서 "visibility"를 "가시성(可視性)"이라고 번역하고 있습니다. "가시성"이라는 용어자체에는 문제가 없습니다만 본 문서에서는 "visibility"라는 용어를 좀 더 쉽게 이해하기 위하여 "가시성" 대신에 "가시범위"라는 용어를 사용하겠습니다. 그리고 가시범위를 좀 더 잘 이해하기 위해서 유효범위(scope;스코프,사용범위)를 먼저 설명하겠습니다.
유효범위(scope)
선언된 멤버(변수, 메쏘드)가 프로그램의 어떤 부분에서 접근할 수 있는지 나타내는 것을 유효범위(scope)라고 합니다.
[code php;gutter:false] <?php $global_var; class my_class { var $class_var; function my_function() { static $local_var; } } ?> [/code]
위의 예제에서 $global_var는 프로그램의 모든 곳에서 접근할 수 있으므로 $global_var의 유효범위는 프로그램 전체가 되며, $class_var는 클래스 my_class에서만 접근할 수 있으므로 $class_var의 유효범위는 클래스 my_class가 되며, $local_var는 메쏘드 my_function에서만 접근할 수 있으므로 $local_var의 유효범위는 메쏘드 my_function이 됩니다.
(수정/추가 2005.10.11)
< 각 변수의 유효범위 >

 \

유효범위

------------------

 변수

\

전역영역 다른 클래스

클래스

my_class

메쏘드

my_function

$global_var

O

O

O

O

$class_var

X

X

O

O

$local_var

X

X

X

O

[ 참고 ]
  1. 메쏘드 my_function이나 다른 전역함수 내에서 전역변수를 사용하기 위해서는 global이라는 키워드로 미리 전역변수임을 선언해주어야 합니다.
  2. 전역변수를 클래스에 정의된 변수에 직접 사용할 수는 없습니다. 그러나 생성자를 이용하면 클래스 유효범위에서 사용하는 것과 같은 효과를 얻을 수 있습니다(이러한 이유로 O를 X로 수정하려다가 △로 수정합니다).
가시범위(visibility)
유효범위가 멤버를 기준으로 그 멤버를 사용할 수 있는 프로그램 영역이라 한다면, 가시범위는 그 반대로 프로그램의 특정영역을 기준으로 그 영역에서 사용할 수 있는 멤버가 무엇인가를 나타내는 것입니다.
위의 예제를 가지고 변수에 대한 가시범위를 나타내면 전역영역의 가시범위는 $global_var이고, 클래스 my_class의 가시범위는 $global_var, $class_var이고, my_function의 가시범위는 $global_var, $class_var, $local_var입니다.
< 각 프로그램영역의 가시범위 >

 \

가시범위

----------------

 프로그램영역

\

$global_var

$class_var

$local_var

전역영역

O

X

X

다른 클래스

O

X

X

클래스 my_class

O

O

X

메쏘드 my_function

O

O

O

유효범위와 가시범위는 보는 관점이 다를 뿐이지 그 본질에 있어서는 동일한 개념입니다.
< 유효범위와 가시범위 >

Posted by 방글24
phpclass/클래스활용2004. 7. 12. 10:08
클래스 | 객체 | 인스턴스
클래스(class) 객체(object) 인스턴스(instance)
객체의 변수와 함수를 정의하는 템플릿 클래스를 실체화시킨 것으로 실제로 기억장소가 할당되어 사용됨 클래스에 정의된 특성을 가지게 되는 객체를 의미하며 일반적으로 객체와 동의어로 사용됨

Posted by 방글24
phpclass/클래스활용2004. 7. 12. 10:05
클래스 상속
기존의 클래스 확장된 클래스
용어 영문 용어 영문

기반클래스

base class

파생클래스

derived class

수퍼클래스

super class

서브클래스

sub class

부모클래스

parent class

자식클래스

child class


Posted by 방글24