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
phpclass/클래스활용2002. 9. 13. 10:24
함수에 의한 모듈화에서는 모듈화 단위가 함수 하나만 가능합니다. 앞에서 살펴보았듯이 2개 이상의 함수를 하나의 모듈로 만들려면 스코프(scope) 및 이름공간(namespace) 문제로 함수로는 불가능하며 이 때는 반드시 클래스를 이용하여야 합니다.
이상과 같이 살펴보았듯이 클래스가 필요할 때가 있고 함수가 필요할 때가 있습니다. 모든 경우에 다 클래스를 사용하는 것은 비효율적일 수 있습니다. 경우에 따라 적절히 선택하는 지혜가 필요합니다.
  1. 함수도 필요없을 만큼 간단한 소스를 작성한다면 함수에 의한 모듈화도 필요없고 구조화 프로그래밍만 하면 됩니다.
  2. 모듈화가 필요하기는 한데 작성된 함수들이 단순히 단타성 함수로만 사용된다면 함수를 이용하여 모듈화하세요.
  3. 모듈화 단위가 여러 개의 함수로 구성된 라이브러리라면 특별한 경우가 아니라면 클래스를 이용하여 모듈화하세요.
여러분에게 PHP에서 클래스를 이용하여 객체지향 프로그래밍을 하라고 권하지는 않겠습니다. 여러분의 판단에 맡기지요. 그러나 클래스를 이용한 모듈화 프로그래밍에는 망설이지 마십시요. 여러분이 생각하는 것처럼 클래스를 이용하였다고 해서 객체지향 프로그래밍이 되는 것은 아닙니다. 그러나 클래스는 모듈화를 위한 훌륭한 도구입니다. 모듈화 도구로써 함수가 삽이라면 클래스는 포크레인입니다.
PHP에서 함수라는 도구를 우리에게 제공하므로서 우리가 함수를 유효적절하게 이용할 수 있었듯이 클래스라는 도구 또한 우리는 최대한 이용하여야 할 것입니다. 클래스는 타도 대상이 아니라 프로그래밍을 하는 우리를 도와주는 친구입니다.

Posted by 방글24
phpclass/클래스활용2002. 9. 13. 10:23
이름공간은 현재 동작하는 프로그램에 정의되어 있는 변수명, 함수명, 클래스명 등과 같은 이름을 기록하기 위한 공간에 관련된 매카니즘을 총칭합니다. PHP에는 아래와 같이 크게 3가지 이름공간이 존재하는 것으로 보입니다.
전역 이름공간 - 함수(또는 클래스) 바깥쪽에서 정의된 이름
지역 이름공간 - 함수(또는 메소드) 안에서 정의된 이름 또는 클래스 안에서 정의된 이름
내장 이름공간 - PHP 자체에 정의된 이름(연산자들과 같은 각종 키워드),
                      함수명과 같이 프로그램 어느 곳에서나 제한없이 접근할 수 있는 이름
이와 같이 이름공간이 독립적으로 분리되어 있으므로 동일한 이름이 서로 다른 지역에 존재할 수 있도록 허용하고 있습니다.
[code php;gutter:false] <?php

$str = "전역 이름공간의 변수";

function test() {
$str = "지역 이름공간의 변수";
echo "$str<BR>\n";

global $str;
echo "$str<BR>\n";
}

test();

?> [/code]
위의 소스와 같이 같은 함수 내에서 지역변수와 전역변수가 동시에 나타난다면 먼저 전역 이름공간을 참조하게 될 것입니다. 따라서 이 소스를 실행하면 아래와 같이 나타날 것입니다. 위의 소스와 같이 함수 내에서 사용되는 변수명은 지역 이름공간에서 찾게 됩니다. 전역 이름공간의 이름을 사용하려면 global 키워드로 먼저 선언해주어야 합니다.
지역 이름공간의 변수
전역 이름공간의 변수
함수마다 별도의 이름공간을 제공해 주기때문에 앞에서 설명한 모듈화가 가능하게 되지요.
만약 이름공간 안에 없는 이름을 참조한다면 어떻게 될까요? 물론 어떻게 처리하는가에 대한 매카니즘은 그 대상이 변수냐 함수냐 등에 의해 다르게 처리되겠지요. 변수인 경우라면 참조한 위치가 전역 위치면 전역 이름공간을 살펴보고 없으면 전역 이름공간에 새로운 이름을 생성합니다. 그리고 참조한 위치가 함수 내와 같은 지역 위치면 해당 함수의 지역 이름공간을 살펴보고 없으면 이 공간에 새로운 이름을 생성합니다.
함수라면 좀더 복잡할 것입니다. 함수를 정의하면서 함수명을 이름공간에 생성하려고 할 때 이미 해당 이름공간에 함수명이 있다면 중복된 함수 정의라는 에러메시지를 보여줄 것입니다. 반면에 함수를 실행하려고 이름공간을 참조하였을 때 이 이름공간에 해당 함수명이 없다면 정의된 함수가 없다고 에러메시지를 보여줄 것입니다.
여러 해동안 웹프로그래밍을 하다보면 나도 모르는 사이에 많은 함수들이 하드디스크에 쌓여가는 것을 볼 수 있습니다. 이 양은 적지 않은 분량으로 이러한 함수를 이용하여 파일 입출력을 다루고, 문자열을 편리하게 처리하도록 도움받게 됩니다.
그런데 이러한 함수의 분량이 쌓여가다보면 개발자는 동일하거나 비슷한 기능의 함수를 다시 작성하는 경우도 빈번하고 더 나아가 동일한 함수명을 사용하는 경우도 발생합니다.
PHP 는 이와 같이 동일한 함수명을 중복하여 정의하여 사용할 경우 에러를 발생시켜 줍니다. 이와 같이 프로그램에서 중복된 이름을 사용할 때 이를 방지하기 위한 매카니즘이 동작하여 이에 의해 중복된 이름을 사용하였을 때 강제적으로 에러를 발생시키도록 하는 것입니다. 이와 같이 해당 이름공간 안에 있는 모든 함수는 자신만의 이름을 가지게 됩니다.
PHP 에서는 대부분 함수를 이용하여 라이브러리를 구축할 때 파일 단위로 묶어 놓게 됩니다. 그런데 파일 단위로 묶여 있는 라이브러리마다 라이브러리 내에서 발생하는 사용자 정의 에러를 처리하기 위하여 에러를 처리하는 함수를 정의하여 사용하게 되지요. 예를 들면 아래와 같이 warning() 함수를 정의하게 됩니다.
[code php;gutter:false] function warning($msg) {
?>
<SCRIPT language=JavaScript>
<!--
window.alert("<?php echo $msg ?>");
//-->
</SCRIPT>
<?php
} [/code]
이러한 에러 처리 함수는 각 라이브러리마다 조금씩 다르게 정의할 수도 있고 때에 따라서는 동일하게 정의할 수도 있겠지요. 그런데 만약 a라는 라이브러리와 b라는 라이브러리에 모두 이와 같은 에러 처리 함수 warning() 함수가 있고 우연히 동일한 웹페이지에서 a와 b 라이브러리를 모두 불러들였다고 하지요. 웹페이지를 실행하면 PHP는 당연히 이름공간 매카니즘에 의해 중복된 함수를 정의하였다는 에러를 신속히 보여줄 것입니다.
여러분은 이러한 에러를 방지하기 위해 나름대로 대책을 세우셨을 것입니다. 에러 처리 함수를 별도의 파일로 구성하여 놓을 수도 있겠지요. 그리고 a와 b 라이브러리에서 에러 처리 함수가 포함된 파일을 포함(include)하겠지요.
아니면 a라는 라이브러리의 에러 처리 함수명을 warning() 대신에 a_warning()로 변경하고, b라는 라이브러리의 에러 처리 함수명을 b_warning()로 변경할 수도 있겠지요.
결국 어떠한 대책이 되었든지간에 함수를 이용하는 한은 불편하기도 하고 실수할 가능성도 상당히 높습니다. 그래서 PHP는 함수라는 도구보다 더욱 강력한 도구인 클래스라는 것을 우리에게 선물로 주었습니다. 위의 예에서 발생한 이름공간 문제를 클래스를 이용하여 해결하여 보지요.
[code php;gutter:false] class a {
function warning($msg) {
?>
<SCRIPT language=JavaScript>
<!--
window.alert("<?php echo $msg ?>");
//-->
</SCRIPT>
<?php
}
}

class b {
function warning($msg) {
?>
<SCRIPT language=JavaScript>
<!--
window.alert("<?php echo $msg ?>");
//-->
</SCRIPT>
<?php
}
} [/code]
여기서 클래스 a와 b가 동일한 파일에 있어도 좋고 다른 파일에 있어도 관계없겠지요. 일단 위와 같이 클래스 a, b 내에 동일한 이름의 에러 처리 함수(메소드) warning()를 정의하여 놓더라도 이름공간 문제가 발생하지 않습니다. 왜냐하면 클래스 a와 b는 서로 다른 이름공간을 가지게 되니까요.
그런데 에러 처리 함수를 클래스의 멤버로 정의하지 않고 일반 함수로 정의하게 되면 이 함수명은 전역 이름공간(global name space)에 있게 됩니다. 동일한 이름공간 내에서는 중복된 이름을 가질 수 없기 때문에 결국 일반 함수로 정의하면 문제가 발생하는 것이지요.
반면 클래스는 각 클래스마다 독립적인 이름공간을 가지기 때문에 함수명이 중복되어도 에러가 발생하지 않습니다. 아울러 클래스에서는 오버로딩, 오버라이딩과 같은 특성을 제공하기 때문에 이름공간의 융통성(?)이 막강하지요.
[주의] PHP에서는 오버로딩을 지원하지 않습니다. 오버라이딩도 너무 포괄적(?)으로 지원합니다.
함수를 통해 모듈화를 하더라도 여러 개의 함수가 모이다보면 함수명의 중복으로 인하여 문제가 발생하는 것입니다. 일반 함수명은 모두 동일한 전역 이름공간에 생성되며 따라서 함수가 많을 때는 중복될 가능성이 많아지게 됩니다. 중복되지 않도록 개발자가 직접 관리해야 하는데 사람이라는 것이 워낙 실수도 많고 기억에도 한계가 있다보니 자연히 한계에 부딪치게 되지요.
결국 여러 개의 함수로 구성된 라이브러리와 같은 경우에서는 라이브러리 전체를 하나의 모듈로 묶어줄 수 있는 강력한 모듈화 도구인 클래스로 감싸줌으로써 함수명의 중복에 따른 문제를 쉽게 해결할 수가 있는 것이지요.

Posted by 방글24
phpclass/클래스활용2002. 9. 13. 10:22
모듈화 프로그래밍에서 우리는 함수를 이용하여 모듈화를 할 수 있다는 것을 알았습니다. 그런데 함수를 이용한 모듈화에는 한계가 있습니다. 하나의 함수 내에서 사용할 변수는 얼마든지 정의하여 사용할 수 있습니다. 즉 지역변수지요. 그런데 만약 2개 이상의 함수에서 공유해야 할 변수가 필요하다면 어떻게 할까요. 전역변수 외에는 방법이 없지요. 그런데 모듈화의 개념이 무엇이라고 앞에서 말씀드렸지요? 바로 블랙박스입니다. 블랙박스 안의 내용은 절대로 불법적(함수를 통한 정상적인 방법으로 접근하지 않는 것을 의미)으로 접근되어서는 안됩니다. 그런데 2개 이상의 함수에서 공유해야할 변수로 전역변수를 이용한다면 이 전역변수는 공유하고 있는 2개 이상의 함수 이외의 곳에서도 얼마든지 접근이 가능하지요. 모듈화 개념에서 벗어나는 것이지요.
아래와 같은 함수가 있다고 가정하지요. 왜 이렇게 작성했는가는 따지지 마세요. 설명하기 위한 것이니까요.
여기에서 $str은 함수 내에서만 사용할 수 있는 지역변수(local variable)입니다. $str 값은 get_string() 함수의 리턴값으로만 반환받을 수 있지 다른 방법으로는 접근할 수가 없습니다. 따라서 이 함수는 모듈화 개념에 맞게 잘 작성된 것입니다.
[code php;gutter:false] function get_string() {
$str = "1234567890";

return $str;
} [/code]
이것을 몇 개의 함수를 이용하여 문자열 자르기를 위한 라이브러리로 확장시켜보지요.
[code php;gutter:false] /*
문자열 자르기를 위한 라이브러리(일반 함수를 이용할 때)
*/

$bank;

function get_string() {
global $bank;
return $bank;
}

function set_string($str) {
global $bank;
$bank = $str;
}

function cut_string($len) {
global $bank;
$bank = substr($bank, 0, $len);
}

set_string("1234567890");
cut_string(4);
echo get_string(); // "1234"가 출력되겠지요. [/code]
set_string() 함수를 이용하여 자르고자 하는 문자열을 지정하고, cut_string() 함수를 이용하여 자를 문자열 길이를 지정하여 자르고, get_string() 함수를 이용하여 자른 문자열을 돌려받습니다.
이와 같이 문자열 자르기를 위하여 몇 개의 함수를 모아서 라이브러리화 시켰더니 모든 함수가 공유해야할 $bank 변수가 필요해 졌습니다.
이렇게 작성된 문자열 자르기 라이브러리를 볼 때 모듈화 관점에서 문제점이 무엇입니까? 앞에서도 언급하였듯이 모듈화가 되려면 함수명, 입력값, 출력값 외에는 외부세계에서 접근이 불가능해야 합니다. 그런데 $bank 변수가 전역변수(global variable)로 사용되다보니 문자열 자르기 라이브러리 외의 어느 곳에서도 쉽게 접근할 수 있는 화이트박스(?)가 되어 버렸지요.
이것이 함수를 이용한 모듈화의 한계입니다. 2개 이상의 함수에서 공유해야할 변수를 블랙박스 내에 담을 수 있는 도구가 바로 클래스입니다. 클래스라는 도구를 통해 모듈화가 보다 완전해 지는 것이지요.
[code php;gutter:false] /*
문자열 자르기를 위한 라이브러리(클래스를 이용할 때)
*/

class string {
var $bank;

function get() {
return $this->bank;
}

function set($str) {
$this->bank = $str;
}

function cut($len) {
$this->bank = substr($this->bank, 0, $len);
}
}

$string = & new string; // 객체 $string의 생성

$string->set("1234567890");
$string->cut(4);
echo $string->get(); // "1234"가 출력되겠지요. [/code]
[주의] PHP 와 C++ 언어에서 클래스를 이용할 때의 모듈화의 완전성을 비교해 볼 때 PHP의 모듈화는 다소 덜 완전합니다. 즉, C++에서는 액세스 권한(access right) 지정자 private를 이용하면 클래스 외부 세계에서는 해당 변수에 절대로 접근할 수 없으나 PHP에서는 아직 액세스 권한 지정자 개념이 도입되지 않았기때문에 객체를 통하여 변수에 접근할 수가 있습니다. 그러나 역시 객체를 통하지 않고는 접근할 수 없다는 면에서 볼 때 일반 함수를 통한 모듈화보다는 훨씬 뛰어난 모듈화 성능을 보여주고 있습니다.
[참고] PHP 가 아닌 C++ 또는 java와 같은 객체지향 프로그래밍에서의 변수의 사용범위는 더욱 다양합니다. 다른 말로하면 복잡하다는 말이기도 하지요. public, private, protected와 같은 액세스 권한 지정자에 의해 클래스 내에서의 사용범위를 조절할 수 있습니다.

Posted by 방글24
phpclass/클래스활용2002. 9. 13. 10:21
우리도 웹 문서를 옛날 GW-BASIC에서 하던 것처럼 함수를 전혀 사용하지 않고도 작성할 수 있습니다. 그런데 왜 함수를 사용합니까? 가장 중요한 것이 모듈화이지요. 입력값과 출력값만 공개되어 있지 내부에서 이 값들이 어떻게 처리되는 지는 알 수 없지요.
요즘 게시판에 가면 심심치않게 등장하는 문자열 자르기 함수를 예로 들어보지요.
[code php;gutter:false] /*
함수명 : cut_string
입력값 : string, length
출력값 : string
기 능 : 지정된 문자열에서 지정된 글자수만큼만 되돌려 준다.
*/

function cut_string($str, $len) {
return substr($str, 0, $len);
} [/code]
이 문자열 함수를 이용하는 개발자에게 필요한 것은 함수명, 입력값, 출력값입니다. 그 외에 함수 내부적으로 입력값이 어떻게 처리되어 출력값을 내보내는지에 대하여는 전혀 알 필요도 없습니다.
만약 이 함수를 개선하여 2바이트 문자(한글 등)도 정상적으로 처리되도록 하기 위해서는 아래와 같이 함수 내부를 수정하여야 할 것입니다. 그러나 이 함수를 이용하고 있는 소스는 전혀 수정할 필요가 없겠지요. 입력값과 출력값이 같으니까요.
[code php;gutter:false] /*
함수명 : cut_string
입력값 : string, length
출력값 : string
기 능 : 지정된 문자열에서 지정된 글자수만큼만 되돌려 준다.
2바이트 문자(한글 등)도 정상적으로 처리되도록 한다.
*/

function cut_string($str, $len) {
if(strlen($str)<$len) {
return $str; //지정된 길이보다 문자열이 작으면 그냥 리턴
}

for($i=0; $i<$len-1; $i++) {
if(ord($str[$i])>127) {
$i++; //한글일 경우 2byte 이동
}
}

return substr($str,0,$i);
} [/code]
이와 같이 함수를 이용하면 함수 내를 하나의 블랙박스로 숨겨놓을 수 있습니다. 외부 세계와는 완전히 차단된 독립적인 세계이지요. 모듈화 프로그래밍은 이와 같이 부분적인 기능들을 모두 블랙박스로 만들어 놓은 후에 이러한 블랙박스를 하나하나 조립하여 전체적으로 완성시켜가는 것입니다.
여러분은 알게모르게 이미 함수를 통해 모듈화 프로그래밍을 하고 있으며 이를 통해 프로그램 개발에 많은 향상과 이점을 가질 수 있었습니다. 이러한 모듈화 개념은 프로그래밍을 하는데 없어서는 안될 무지무지하게 중요한 개념이지요. 함수를 통해 구현되는 모듈화는 함수 내의 정보를 외부세계와 독립적으로 구성하기 위한 것이며 다른 말로 하면 함수 내의 정보를 숨기기 위한 것입니다.
객체지향 프로그래밍에서의 캡슐화(encapsulation)라는 개념도 모듈화 개념과 비교할 때 그 역할이 동일합니다. 즉 블랙박스화이지요. 단지 블랙박스화 하기 위한 도구와 그 대상이 다를 뿐입니다. 모듈화의 도구로 함수를 이용하였듯이 캡슐화의 도구로 클래스를 이용할 뿐입니다. 캡슐화에 대하여는 더 이상 깊이 들어가지 않겠습니다. 그러나 분명히 이해하여야 할 것은 그 역할이 모듈화와 동일하다는 것입니다. 그래서 이 문서에서는 앞으로 클래스를 이용한 캡슐화를 그냥 모듈화라고 부르기로 하겠습니다.
이제는 아래와 같은 도식을 얻을 수 있겠지요.
모듈화 = 캡슐화 = 블랙박스화

Posted by 방글24
phpclass/클래스활용2002. 9. 13. 10:20
1990 년대초에 객체지향 프로그래밍(Object-Oriented Programming)이라는 방법이 나타나기 전까지는 파스칼 또는 C를 중심으로한 구조화/모듈화 프로그래밍(Structured/Modular Programming)이 전세계를 지배하고 있었습니다.
2002 년을 보내고 있는 현시점까지도 웹프로그래밍 언어인 PHP에서는 구조화/모듈화 프로그래밍의 지배를 받고 있지요. 그러나 구조화/모듈화 프로그래밍에는 많은 문제가 있기 때문에 PHP도 객체지향 프로그래밍쪽으로 점점 무게가 실리게 될 것입니다.
어쨌든지간에 현재까지도 PHP를 지배하고 있는 구조화/모듈화 프로그래밍에 대하여 먼저 알아보고 그 다음에 과연 구조화/모듈화 프로그래밍을 할 때도 과연 객체지향 프로그래밍의 도구인 클래스를 사용해야 하는가에 대하여 숙고해 보도록 하겠습니다.
그럼 우선 클래스의 필요성을 살펴보기 전에 구조화/모듈화 프로그래밍에 대하여 살펴보도록 하겠습니다.
1970 년대에 제안된 구조적 기법(구조화/모듈화 프로그래밍)을 통하여 프로그래머는 체계적인 방법으로 보다 쉽게 프로그램을 작성할 수 있을 뿐만 아니라, 일단 작성된 프로그램은 누구나가 쉽게 읽고 이해할 수 있어서 이후에 프로그램을 쉽게 수정할 수 있었습니다.
구조화 프로그래밍(Structured Programming)
프로그램이 커지고, 기능이 복잡해지면 개발 뿐만 아니라 수정과 유지 보수에 오히려 더 많은 시간과 노력이 필요하게 됩니다. 이러한 문제에 대처하기 위하여 프로그램의 구조를 순차, 선택, 반복 제어 구조만으로 설계하여 처리 절차를 간단하고 명료하게 표현할 수 있는 구조화 프로그래밍 기법이 나타나게 되었습니다.
▶순차 처리
▶선택 처리
▶반복 처리
그 옛날 BASIC에서의 Go To문과 같은 분기를 허용하지 않고 일의 순서에 따라 시작부터 끝까지 한 방향으로 진행하도록 처리하는 것이 "순차 처리"이며, if 또는 switch 문과 같이 주어진 조건에 따라 명령문을 선택하여 처리하는 구조가 "선택 처리"이며, while, for next 문과 같이 주어진 조건을 만족할 때까지 일정한 범위의 명령문들을 반복 수행하는 구조가 "반복 처리" 구조입니다.
구조화 프로그래밍은 프로그램의 구조가 논리적으로 구성되어 있어 아래와 같은 특징을 가지게 됩니다.
▶코딩이 쉽다(분석,설계,제작)
▶프로그램을 읽기 쉽게 한다(가독성)
▶테스트를 쉽게 한다(테스트)
▶수정하기 쉽다(유지 보수)
모듈화 프로그래밍(Modular Programming)
프로그램을 작성할 때 큰 프로그램을 한번에 작성하는 것이 아니라 기능별로 나누어 우선 부분별 작성을 한 다음, 각각의 작은 프로그램들을 서로 연결시켜 하나의 완성된 프로그램을 만드는 방법으로 기능별로 나누어진 각 모듈은 각각 이 하나의 기능을 수행하며 그 기능을 수행하기 위하여 필요한 모든 코드와 변수를 포함하도록 하는 프로그래밍 방식입니다.
프로그램 덩치가 큰 프로그램을 모듈별로 나누지 않고 단지 구조화 프로그래밍만을 이용하여 하나로 작성하기는 무척 어렵습니다. 그러나 구조화 프로그래밍을 적용하기 전에 먼저 모듈화 프로그래밍을 적용한 후에 각 모듈별로 구조화 프로그래밍을 적용하게 되면 그 구현이 매우 쉽게 됩니다.
모듈화 프로그램밍은 아래와 같은 특징을 가짐으로 말미암아 구조화 프로그래밍과 마찬가지로 프로그램의 구조가 논리적으로 구성되어 있어 프로그램의 작성/수정이 용이하고, 이해하기가 쉽습니다.
▶하나의 모듈은 유일한 하나의 입구(Entry point)와 유일한 출구(Exit point)를 갖는다.
▶하나의 모듈은 독립적인 구조를 갖는다.
   (프로그램내에서 하나의 독립적인 기능을 수행)
▶모듈은 개별적으로 테스트가 가능하다.

Posted by 방글24
phpclass/클래스활용2002. 9. 13. 10:09
부제:클래스를 이용한 모듈화 프로그래밍
PHP 를 가지고 웹프로그래밍을 하면서 과연 클래스를 사용해야 하는지에 대하여 살펴보겠습니다. 클래스가 객체지향 프로그래밍의 도구이기는 하지만 여기서는 객체지향개념을 도입하지 않고 구조화/모듈화 프로그래밍에서의 모듈화 개념, 좀더 구체적으로 말하면 스코프(scope)와 이름공간(name space)이라는 개념을 가지고 클래스를 사용할 필요가 있는지에 대하여 살펴보고자 합니다. 객체지향개념을 가지고 클래스를 사용해야 한다고 설명하면 반론이 만만치(?) 않을 것이기 때문에 가능한한 불필요한 논쟁을 피하고자 합니다.
본인의 전공이 컴퓨터 공학 내지는 소프트웨어 공학이 아닌 고로 이론적인 면에 서투른 점이 많이 보일 것입니다. 그러한 부분은 기탄없이 지적하여 주시면 감사하겠습니다.

Posted by 방글24