phpclass/객체모델2002. 12. 21. 15:10
비공개 멤버 변수(Private Members Variable)
접근 권한(Access Right)
C++ 또는 자바와 같은 객체지향 프로그래밍 언어에는 멤버에 대한 접근 권한을 지정하는 public, protected, private라는 접근지정자(또는 접근제한자,접근변경자)가 있습니다. 여러분이 작성하고자 하는 코드를 더 잘 캡슐화하기 위하여 접근지정자를 통해 멤버(메소드 및 변수)에 대한 접근을 제어하는 것입니다.
private : 자신 클래스 안에서만 접근할 수 있으며 하위 클래스에서는 접근할 수 없다.
protected : 자신 클래스 및 하위 클래스에서만 접근할 수 있다.
public : 모든 클래스에서 접근할 수 있다.
C++ 이냐 자바냐에 따라 그 의미가 약간씩 다르기도 하고 추가되는 개념도 있습니다. 가장 큰 차이점은 protected 접근지정자로 C++에서는 바로 아래에 있는 하위 클래스에서만 접근할 수 있는 반면에 자바에서는 패키지라는 개념이 도입되어 패키지 안에 있는 어떤 클래스도 접근할 수 있게 해 줍니다.
PHP에서의 접근 권한 지정
Zend 엔진 1.0에서는 멤버변수를 정의할 때 아래와 같이 var 키워드를 이용하게 됩니다. 이와 같이 접근지정자를 별도로 지정할 수 없으며 무조건 public 특성을 가지게 됩니다.
[code php;gutter:false] var $member; [/code]
Zend 엔진 2.0에서 추가된 키워드인 static으로 지정된 정적멤버변수의 경우에도 public 특성을 가지기 때문에 외부클래스에서 자유롭게 접근할 수 있습니다.
[code php;gutter:false] static $static_member; [/code]
앞서 작성된 "클래스를 사용해야하나?(부제:클래스를 이용한 모듈화 프로그래밍)"라는 글에서함수 내부의 정보를 숨기기위한 모듈화를 소개하면서 같은 개념으로 객체 수행의 내부 동작을 숨기기 위한 캡슐화를 살짝 언급하였었지요. 이러한 캡슐화를 통해 정의된 인터페이스를 통해서만 객체 내부에 접근하도록 허용하는 것입니다.
함수의 모듈화를 위해 전역변수가 아닌 지역변수가 요구되듯이 클래스의 캡슐화를 위해서는 public이 아닌 자신의 클래스 내에서만 접근할 수 있는 private라는 접근지정자가 절실히 요구되지요.
Zend 엔진 2.0에서는 접근지정자 private를 추가하여 캡슐화 도구로써 진일보하게 되었습니다. 멤버변수를 private로 지정하게 되면 멤버변수가 선언된 클래스 외부에서는 이 멤버 변수에 절대로 접근할 수가 없게 됩니다.
[code php;gutter:false] <?php
class MyClass {
private $Hello ="Hello, World! \n";

function printHello() {
print $this->Hello;
}
}

class MyClass2 extends MyClass {
function printHello() {
MyClass::printHello(); /* Should print */
print $this->Hello; /* Shouldn't print out anything */
}
}

$obj = new MyClass();
print $obj->Hello; /* Shouldn't print out anything */
$obj->printHello(); /* Should print */

$obj = new MyClass2();
print $obj->Hello; /* Shouldn't print out anything */
$obj->printHello();
?> [/code]

Posted by 방글24
phpclass/객체모델2002. 12. 21. 14:52
정적 멤버변수(Static Class Member Variables)
정적 멤버변수의 필요성
생성된 모든 인스턴스들이 공유하는 공통적인 정보가 필요할 때에 사용되는 것이 정적 멤버변수입니다. 정적 멤버변수는 다른 일반 멤버변수와 달리 각각의 인스턴스에 기억장소가 할당되는 것이 아니라, 단 한 개의 기억장소만이 할당되고 모든 인스턴스에 의하여 공유되거나 인스턴스없이 바로 참조할 수 있습니다.
클래스 스코프
정적 멤버변수는 객체 내의 멤버 변수로서 확보 되는것이 아니라, 별도의 영역(클래스 영역)에 확보 되어지는 멤버변수입니다. '클래스와 인스턴스' 글에서 '클래스와 인스턴스 개념을 이용한 객체의 모델링'을 설명하면서 아래와 같은 그림을 보신 적이 있을 것입니다.
< 클래스와 인스턴스 개념을 이용한 객체의 모델링 >
이 그림을 가지고 정적 멤버변수를 모델링하게 되면 아래와 같을 것입니다.
< 클래스와 인스턴스 개념을 이용한 객체의 모델링 >
객체를 생성할 때마다 정적 멤버변수인 '$차량대수'를 한 대씩 증가시키는 코드에서 '$둘리', '$밍키', '$후키' 객체를 생성하게 되면 정적 멤버변수 '$차량대수'는 3이 저장되어 있을 것입니다. 이와 같이 모든 객체가 공유할 필요가 있는 멤버변수를 정적 멤버변수로 지정하게 되면 어떠한 객체에서 접근하더라도 동일한 멤버변수에 접근할 수 있습니다. 즉, '$둘리->차량대수', '$밍키->차량대수', '$후키->차량대수'는 모두 동일한 멤버변수를 가르키고 있습니다.
Zend 엔진 1.0에서의 정적 멤버변수
Zend 엔진 1.0에서 객체 인스턴스 대신에 클래스명을 통해 클래스 메소드(class method), 즉 정적 멤버함수를 호출할 수 있었으나 객체 인스턴스가 아닌 클래스명을 통하여 클래스 스코프를 갖는 변수에 접근할 수 있는 방법을 지원하지 않았습니다.
정적 멤버함수가 다루어야 할 가장 기본적인 요소(멤버)는 정적 멤버변수입니다. 정적 멤버변수 역시 정적 멤버함수와 마찬가지로 객체와 관계없이 클래스 스코프(사용범위)를 가지고 있기 때문에 정적 멤버함수에서 다룰 수 있는 유일한 멤버변수입니다.
그러나 Zend 엔진 1.0에서 정적 멤버함수만 제공하고 정적 멤버변수를 지원하지 않았기 때문에 정적 멤버함수의 기능을 온전히 이용하기에는 한계가 있었습니다. 예를 들면 각종 문자열 처리 메소드를 모아놓은 라이브러리와 같이 멤버변수가 필요없는 경우에 한하여 정적 멤버함수 기능을 이용할 수 있었지요.
정적 멤버변수의 정의
클래스를 정의할 때 'var' 키워드로 정의되는 멤버변수는 클래스가 인스턴스화할 때마다 새로 만들어지는 인스턴스 변수입니다. 따라서 한 인스턴스 변수에 접근하려면 먼저 그 클래스의 인스턴스를 'new'라는 키워드로 생성해서 접근해야 합니다.
만약 모든 클래스간에 공유하여야 할 변수가 필요하다면 어떻게 할까요. Zend1 엔진에서는 이를 지원하지 않았었으나 2002년 6월경 릴리즈된 Zend 엔진 2.0 알파2 버전에 의하면 Zend2 엔진에서는 클래스간에 공유할 변수를 정의할 수 있게 되었습니다. 이를 위한 키워드가 'static'이며 다음과 같은 형식으로 정의됩니다.
<형식> static 변수명 = 변수값;
정적 멤버변수를 이용하기
일반 멤버변수는 클래스만 선언한다고 해서 호출할 수 있는 것이 아니라 반드시 객체를 생성한 후에 인스턴스를 통하여 호출되어야 합니다. 반면 정적 멤버변수는 인스턴스가 없어도 호출할 수 있습니다. 정적 멤버변수는 특정 인스턴스를 대상으로 수행되는 것이 아니고 위에서 설명한 클래스 스코프를 갖는 멤버이기 때문에 인스턴스없이도 호출이 가능합니다.
정적 멤버변수는 그 클래스 자체에 전역적(클래스 스코프)이며 다른 클래스나 객체에 서로 사용될 수 있습니다. 그래서 정적 멤버변수는 그 클래스의 인스턴스가 있든 없든 상관없이 어느 곳에서나 사용될 수 있는 것입니다. 이러한 경우에는 정적 멤버변수를 정의하고 있는 클래스의 이름을 범위연산자(scope resolver) "::"와 연결되어 사용되어야 합니다.
<형식> 클래스명::정적멤버변수
[code php;gutter:false] class Logger {
static $m_Instance = NULL;

function Instance() {
if (Logger::$m_Instance == NULL) {
Logger::$m_Instance = new Logger();
}

return Logger::$m_Instance;
}

function Log() {

}
};

$Logger = Logger::Instance();
$Logger->Log(); [/code]
따라서 '클래스 스코프'의 예제에서 정적 멤버변수 $차량대수는 앞 항목 '클래스 스코프'의 예와 같이 $둘리->차량대수, $밍키->차량대수, $후키->차량대수와 같이 참조할 수도 있으나 '클래스명::차량대수'와 같이 인스턴스없이 참조할 수도 있습니다. 어떻게 참조하든지 동일한 멤버를 다루게 되는 것이지요. 이와 같이 정적 멤버변수가 클래스 스코프를 갖는다는 의미에서 자바에서는 이 변수를 클래스 변수라고 호칭합니다.

Posted by 방글24
phpclass/객체모델2002. 12. 21. 14:50
개선된 객체모델(Revamped object model)
객체 핸들(object handle)
Zend 엔진 1.0 객체 모델에서는 생성된 객체를 값으로 취급하도록 설계되어 있습니다. 이것은 프로그래머가 변수에 값을 할당하거나 함수에 인수를 전달하는 것과 같은 조작을 할 때 정수와 문자열과 같은 다른 기본형(primitive types)을 다루는 것과 같은 방법과 매우 유사하게 객체를 다룬다는 것을 의미합니다. 이것은 모든 객체가 복사되고 있다는 것을 의미합니다.
반면에 자바에서는 값이 아닌 핸들을 가지고 객체를 참조합니다. 핸들이란 객체 ID라고 생각할 수 있지요. 제 홈페이지에서 설명하고 있는 '참조(레퍼런스)' 정보에서 일부 언급하였듯이 자바에서는 객체를 변수에 할당하거나, 객체를 매개변수로 메소드에 전달하거나 메소드로부터 반환할 때, 전달되는 것은 이러한 객체의 참조(레퍼런스)이지 객체의 복사본이 아닙니다.
그러나 PHP3 또는 PHP4에서는 객체 핸들이 아닌 객체 자체를 다루도록 모델링되어 있기 때문에 객체를 다루는데 있어서 매우 비효율이며 소멸자와 같은 객체 특성을 구현하는데 많은 문제가 발생합니다. 결국 객체를 다룰 때는 자바에서와 같이 참조로 전달하는 것이 효율적이며 이와같이 객체 모델을 핸들 지향 모델(handle oriented model)로 변경하게 되면 어드레싱을 하는데 있어 소멸자, 메소드 반환값으로 역참조하기(de-referencing method return values), 객체 복사(object duplication)에 관하여 매우 엄격히 제어할 수 있는 등 객체와 관련된 많은 요구를 수용할 수 있게 됩니다.
새로 제안된 객체 모델은 자바 모델에 의해서 매우 많이 영향을 받습니다. 일반적으로, 새로운 객체를 생성할 때 객체 그 자체대신에 해당 객체의 핸들을 얻게 될 것입니다. 이 핸들을 함수에 전달하고, 할당하고 복사하였을 때 복사되고 보내지고 할당되는 것은 핸들만 입니다. 객체 자체는 결코 복사 또는 중복되지 않습니다.
이것은 한 객체의 모든 핸들이 항상 동일한 객체를 지정하도록 하기 때문에 객체를 다루는데 의미가 분명해지며 불필요한 중복과 혼란스러운 동작을 줄여줄 수 있습니다.
Zend 엔진 1.0 객체 모델
앞에서도 설명하였지만 PHP4에 탑재된 Zend 엔진 1.0 객체 모델에서는 생성된 객체를 값으로 취급하도록 설계되어 있습니다.
다음 코드가 Zend 엔진 1.0에서 어떻게 동작하는지 살펴보겠습니다.
[code php;gutter:true] class MyClass {
function setMember($value) {
$this->member = $value;
}

function getMember() {
return $this->member;
}
}

function foo($obj) {
$obj->setMember("foo");
}

$object = new MyClass();
$object->setMember("bar");
foo($object);
print $object->getMember(); [/code]
16행에서 객체의 멤버변수 member은 문자열 "bar"을 값으로 설정됩니다. 17행에서 객체 $object가 함수 foo에 값에 의해 보내질 때(call by value) 객체는 복제(duplicate)됩니다. 그러므로 foo()를 호출하면 $object의 복제물을 가지고 12행에서 $obj->setMember("foo")를 호출하게 될 것입니다. 그러면 18행에 의해 출력된 결과는 "bar"가 될 것입니다.
이것이 오늘날까지 PHP3 또는 PHP4 스크립팅 엔진이 동작하던 방식입니다. 어쩌면 많은 개발자들이 아직까지도 PHP3 또는 PHP4에서 항상 동일한 객체를 다루지 않고 복제된 객체를 다룬다는 사실 조차도 눈치채지 못하였을 수도 있을 것입니다. 제 홈페이지 '참조(레퍼런스)' 기사를 주의깊게 읽어본 독자라면 이 문제에 대하여 아래와 같이 복제 대신에 참조에 의한 객체 전달을 통하여 해결할 수 있다는 것을 알았겠지요.
[code php;gutter:true] class MyClass {
function setMember($value) {
$this->member = $value;
}

function getMember() {
return $this->member;
}
}

function foo(&$obj) {
$obj->setMember("foo");
}

$object = new MyClass();
$object->setMember("bar");
foo($object);
print $object->getMember(); [/code]
위의 참조(레퍼런스)를 이용한 개선된 예제에서 객체 생성할 때의 발생하는 객체 복제의 비효율성까지 추가로 개선코자 한다면 15행의 '$object = new MyClass();' 대신에 '$object = & new MyClass();'라고 코딩하였을 수도 있었겠지요.
Zend 엔진 2.0에서의 개선된 객체 모델
개선된 Zend 엔진 2.0 객체 모델에서는 이전과 같이 객체를 다루지 않아도 됩니다. 객체 모델의 커다란 변화에도 불구하고 객체의 기본적인 사용법은 참조기호 & 없이 이전 버전의 스크립트 엔진에서와 거의 동일할 것입니다. 새로운 객체 인스턴스를 생성하고 사용하기 위해서는 다음과 같이 합니다.
[code php;gutter:false] $object = new MyClass();
$object->method(); [/code]
위의 코드에서 클래스 MyClass의 새로운 인스턴스에 대한 핸들을 $object에 할당할 것이고 새로운 인스턴스에 대한 메소드를 호출할 것입니다.
[code php;gutter:true] class MyClass {
function setMember($value) {
$this->member = $value;
}

function getMember() {
return $this->member;
}
}

function foo($obj) {
$obj->setMember("foo");
}

$object = new MyClass();
$object->setMember("bar");
foo($object);
print $object->getMember(); [/code]
새로운 객체 모델은 코드의 직관적인 구현을 훨씬 더 많이 허용할 것입니다. 17행에서 객체 핸들(ID)이 값으로 foo()에 전달됩니다. foo() 내부에서 객체는 이 핸들에 의하여 가져오므로 setMember() 메소드는 원래의 인스턴스화된 객체를 호출하는 것이며 복사본으로 호출하는 것이 아닙니다. 그러므로 18행에 의해 "foo"가 출력될 것입니다.
이러한 접근은 객체가 생성되고 복제될 때 개발자에게 좀더 엄격하게 관리하도록 해줍니다. 이와 같이 객체 핸들을 foo()에 전달하여 객체를 다루도록 하면 불필요한 객체 복제를 줄여줄 것이고 이에따라 실행시간 성능을 부가적으로 개선시킬 것입니다.

Posted by 방글24
phpclass/객체모델2002. 12. 21. 14:42
Zend 엔진 2.0의 새로운 객체 모델
앞서 작성된 "클래스를 사용해야하나?(부제:클래스를 이용한 모듈화 프로그래밍)"라는 글에서 언급했던 것과 같이 현재 Zend 엔진 1.0을 기반으로하는 PHP4에서 제공되는 객체 관련 기능들이 여러가지로 부족한 면이 많이 있었습니다.
이에 따라 www.zend.com에서는 개선된 객체 모델을 도입한 Zend 엔진 2.0이 개발 중에 있습니다. 2001년 11월에 발표된 Zend 엔진 2.0 설계 초안(Zend Engine 2.0 Design Draft)과 2002년 6월에 릴리즈된 Zend 엔진 2.0 알파2 버전(Alpha 2 of PHP w/ the Zend Engine 2 Now Available)에서 개선된 내용을 정리해 보면 대략 아래와 같이 세가지로 분류할 수 있습니다.
  • 개선된 객체 모델(Revamped Object Model)
  • 예외상황 처리(Exception Handling)
  • 향상된 외부 지원 객체지향 APIs(Improved Interface with 3rd party OO APIs)
분류에 포함되지 않은 String offset syntax와 같은 문법 변경 사항들이 일부 있으나 변경된 내용을 살펴보면 새로운 객체 모델을 구현하기 위한 기술에 거의 집중되고 있음을 볼 수 있습니다. 이 문서에서는 개선된 객체 모델에 대하여 집중적으로 살펴보고자 합니다.
Zend 엔진 2.0에 추가된 주된 기능 중에서 예외상황 처리(exception handling) 및 자바 또는 닷넷과 같은 외부 기술에 관한 사항은 관련문서를 참조하기 바라며
외부 객체지향 APIs(COM 컴포넌트 또는 자바 객체)에 대하여는 OO Syntax Overloading 기술로  접근할 수 있도록 Zend 엔진 2.0를 개발하고 있으며 이 기술은 객체역참조(Object Dereferencing)라는 객체지향 개념을 통해 구현하고 있습니다.
Zend 엔진 2.0에서 지원하는 객체 특성을 살펴보면 아래 표와 같이 설계 초안에서 알파2 버전으로 넘어오면서 다중상속 특성이 빠진 반면 nested namespace 개념(nested 클래스, import 처리 등)이 추가되었습니다.
< PHP의 객체지향 프로그래밍 특성 >
객체 특성 PHP3 or
Zend 엔진1.0
Zend 엔진 2.0
설계초안
Zend 엔진2.0
알파2

객체 핸들
revamped object model using object handles

객체복사

객체참조

객체참조

static 멤버 변수
static class member variables

x

o

o

private 멤버 변수
private member variables

x

o

o

단일화된 생성자
unified constructors

x

o

o

소멸자
destructors

x

o

o

객체 복제
object cloning

N/A

o

o

함수 반환 객체 역참조
dereferencing objects returned from functions

x

o

o

객체 삭제
forced deletion of objects

x

o

o

Nested 클래스
nested classes

x

x

o

클래스 상수
class constants

x

x

o

다중 상속
multiple Inheritance

x

o

x

(o:포함됨, x:포함되지 않음, N/A:Non Applicable)
현재도 Zend 엔진 2.0의 모든 특성들에 대하여 www.zend.com 웹사이트와 메일링 리스트(engine2-subscribe@lists.zend.com)를 통해 계속 토론되어지는 과정에 있으므로 앞으로 발표될 Zend 엔진 2.0의 최종안에서는 새로운 특성들이 포함될 수도 있으며 반대로 현재 포함되어 있는 특성들이 제외될 수도 있습니다.
참고 자료

Posted by 방글24