phpclass/객체모델2002. 12. 21. 15:21
이름공간(namespace)
이름공간은 현재 동작하는 프로그램에 정의되어 있는 상수명, 변수명, 함수명, 클래스명 등과 같은 이름을 기록하기 위한 공간에 관련된 매카니즘을 총칭하는 것으로 이러한 이름을 기록하기 위한 심볼 테이블을 관리합니다.
Zend 엔진 1.0에서의 스코프
Zend 엔진 1.0에서는 아래와 같이 3가지의 스코프(유효 범위)만 제공하였습니다.
  • 전역 스코프(global scope)
  • 클래스 스코프(class scope)
  • 함수 스코프(function scope)
변수는 모든 스코프에 다 포함될 수 있으며, 함수는 클래스 및 전역 스코프에만 포함될 수 있으며, 상수 및 클래스는 단지 전역 스코프에만 포함될 수 있습니다.
< 각 스코프의 특성 (o:포함가능, x:포함불가능) >
멤 버 전역 스코프 클래스 스코프 함수 스코프
변  수

o

o

o

함  수

o

o

x

클래스

o

x

x

상  수

o

x

x

이것은 Zend Engine 1.0의 모든 스코핑 방식이 심볼 이름의 충돌 문제를 해결하는데는 본질적으로 제한적이었다는 것을 의미합니다.
Zend 엔진 2.0에서의 스코프
Zend 엔진 2.0에서는 클래스 안의 클래스(Nested class)가 가능해졌다고 앞에서 살펴본 바 있습니다. 이는 바로 nested 이름공간(nested namespace)을 지원함으로 그 의미가 분명해 지는 것이지요. nested 이름공간 개념을 도입하여 모든 종류의 심볼을 포함하는 다중 심볼 테이블을 정의할 수 있도록 함으로써 심볼의 충돌의 문제를 해결할 수 있도록 한 것입니다.
< 각 스코프의 특성 (o:포함가능, x:포함불가능) >
멤 버 전역 스코프 클래스 스코프

함수 스코프

변  수

o

o

o

함  수

o

o

x

클래스

o

o

x

상  수

o

o

x

Zend 엔진 2.0에서는 현재의 클래스 이름공간을 인식하고 있으며 심볼을 탐색할 때 현재의 이름공간의 심볼테이블을 우선적으로 찾게됩니다.
현재 이름공간의 심볼 테이블을 가장 먼저 탐색하게 됩니다. 따라서 아래의 예에서 보면 클래스 FooClass 내에서는 클래스 상수 foo가 같은 이름의 전역 상수 foo를 덮어 버리기 때문에 'bar'가 아니라 'foobar'을 출력합니다.
[code php;gutter:false] <?php
define('foo','bar');

class FooClass {
const foo = 'foobar';

function printFoo() {
print foo;
}
}
?> [/code]
[code php;gutter:false] <?php
class FooClass {
function foo() {
$this->bar();
bar();
}

function bar() {
print "foobar\n";
}
}

$obj = new FooClass;
$obj->foo();
?> [/code]
아래의 예에서 bar()의 경우를 보면 Zend 엔진 1.0에서는 전역 스코프를 갖는 전역함수 bar()를 찾았을 것입니다. 그러나 Zend 엔진 2.0에서는 먼저 클래스 스코프를 갖는 메소드 bar()를 찾습니다.
따라서 위의 소스를 실행하게 되면 bar() 메소드가 현재의 이름공간에 존재하기 때문에 "foobar"를 2번 출력합니다.
접근자(accessor)
self::
클래스 지역 심볼에 접근하기 위해서 아래의 예와 같이 클래스 접근자(class accessor) 'self::'를 이용할 수 있습니다. 여기서 self::$my_static_name는 현재 클래스에 정의되어 있는 멤버변수를 의미하며 self::MY_CONSTANT는 현재 클래스에 정의되어 있는 클래스 상수를 의미합니다.
[code php;gutter:false] self::$my_static_name = self::MY_CONSTANT; [/code]
클래스명::
self 접근자 대신에 MyClass:과 같은 클래스의 이름을 사용할 수 있습니다.
[code php;gutter:false] MyClass::$my_static_name = MyClass::MY_CONSTANT; [/code]
상수 및 함수에 접근할 때 클래스를 지정하지 않는다면 현재의 클래스에서 먼저 찾게될 것입니다. 만약 현재 클래스에서 해당 심볼을 찾지 못한다면 그 다음에는 전역 스코프에서 찾을 것입니다. 따라서 전역 함수와 같은 이름으로 메소드를 정의할 때에는 주의할 필요가 있습니다.
main::
만약 현재 위치에 관계없이 전역 스코프에서만 찾기를 원한다면 main:: 접근자를 이용하면 됩니다.
[code php;gutter:false] main::strlen();
main::MY_CONSTANT [/code]
예를 들면 main::strlen()은 main 스코프에 있는 strlen() 함수를 호출하게 됩니다.
import 키워드
상수, 함수 또는 클래스를 매우 자주 사용하는데 타자속도가 매우 느리기때문에 때로는 클래스 접근자(예를 들면 MyClass ::)를 통해 이러한 심볼에 다루는 것이 불편할 수도 있습니다. 이러한 경우에는 import 키워드를 가지고 다른 이름공간에 있는 함수, 클래스 및 상수를 현재의 이름공간으로 손쉽게 가져올 수 있습니다.
[code php;gutter:false] <?php
class MyClass {
class MyClass2 {
function hello() {
print "Hello, World in MyClass2\n";
}
}

function hello() {
print "Hello, World\n";
}
}

import function hello, class MyClass2 from MyClass;

MyClass2::hello();
hello();
?> [/code]
 클래스 MyClass의 내부클래스로 정의된 MyClass2는 클래스 MyClass 외부에서는 접근할 수 없습니다. 즉, MyClass에 해당하는 이름공간의 심볼 테이블에만 기록되어 있으므로 다른 이름공간에서는 접근할 수 없는 것이지요. 그러나 import class MyClass2 from MyClass;와 같이 import 키워드를 이용하여 MyClass 이름공간에 있는 심볼 MyClass2를 전역 이름공간으로 가져올 수 있기 때문에 MyClass2::hello();와 같이 MyClass2를 전역 스코프로 접근할 수 있습니다.
클래스 MyClass의 멤버로 정의된 hello() 메소드도 원래 '객체->' 또는 '클래스명::'을 통하지 않고는 접근할 수 없으나 import function hello from MyClass;와 같이 import 키워드를 이용하게 되면 hello 함수 심볼을 전역 이름공간으로 가져올 수 있기 때문에 전역 스코프를 갖는 메인함수처럼 hello();와 같이 메소드명만으로 호출할 수 있습니다.
[code php;gutter:false] <?php
class MyOuterClass {
class MyInnerClass {
function func1() {
print "func1()\n";
}

function func2() {
print "func2()\n";
}
}
}

import class * from MyOuterClass;
import function func2 from MyOuterClass::MyInnerClass;

MyInnerClass::func1();
func2();
?> [/code]
 클래스 MyOuterClass의 정의된 모든 심볼을 가져오려면 '*' 기호를 이용합니다. 내부클래스에 있는 심볼을 가져오기위해서는 내부클래스의 이름공간을 '외부클래스::내부클래스'로 표기하여 가져올 수 있습니다.
[code php;gutter:false] <?php
class MyOuterClass {
const Hello ="Hello, World\n";
}

import const Hello from MyOuterClass;
print Hello;
?> [/code]
위의 예는 클래스 MyOuterClass에 정의된 상수 Hello를 전역 이름공간으로 가져오는 예입니다.

Posted by 방글24