English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
PHP 命名空间(namespace)是在PHP 5.3中加入的,如果你学过C#和Java,那命名空间就不算什么新事物。 不过在PHP当中还是有着相当重要的意义。
PHP 命名空间可以解决以下两类问题:
用户编写的代码与PHP内部的类/函数/常量或第三方类/函数/常量之间的名字冲突。
为很长的标识符名称(通常是为了缓解第一类问题而定义的)创建一个别名(或简短)的名称,提高源代码的可读性。
默认情况下,所有常量、类和函数名都放在全局空间下,就和PHP支持命名空间之前一样。
命名空间通过关键字namespace 来声明。如果一个文件中包含命名空间,它必须在其它所有代码之前声明命名空间。语法格式如下;
<?php // 定义代码在 'MyProject' 命名空间中 namespace MyProject; // ... 代码 ...
你也可以在同一个文件中定义不同的命名空间代码,如:
<?php namespace MyProject; const CONNECT_OK = 1; class Connection { /* ... */ } function connect() { /* ... */ } namespace AnotherProject; const CONNECT_OK = 1; class Connection { /* ... */ } function connect() { /* ... */ } ?>
不建议使用这种语法在单个文件中定义多个命名空间。建议使用下面的大括号形式的语法。
<?php namespace MyProject { const CONNECT_OK = 1; class Connection { /* ... */ } function connect() { /* ... */ } } namespace AnotherProject { const CONNECT_OK = 1; class Connection { /* ... */ } function connect() { /* ... */ } } ?>
将全局的非命名空间中的代码与命名空间中的代码组合在一起,只能使用大括号形式的语法。全局代码必须用一个不带名称的 namespace 语句加上大括号括起来,例如:
<?php namespace MyProject { const CONNECT_OK = 1; class Connection { /* ... */ } function connect() { /* ... */ } } namespace { // 전체 코드 session_start(); $a = MyProject\connect(); echo MyProject\Connection::start(); } ?>
声明命名空间之前唯一合法的代码是用于定义源文件编码方式的 declare 语句。所有非 PHP 代码包括空白符都不能出现在命名空间的声明之前。
<?php declare(encoding='UTF)-8'); //여러 네임스페이스와 네임스페이스에 포함되지 않은 코드를 정의합니다 namespace MyProject { const CONNECT_OK = 1; class Connection { /* ... */ } function connect() { /* ... */ } } namespace { // 전체 코드 session_start(); $a = MyProject\connect(); echo MyProject\Connection::start(); } ?>
다음 코드는 문법 오류가 발생합니다:
<html> <?php namespace MyProject; // 네임스페이스 앞에 "<html>"가 있으면 결정적인 오류가 발생합니다 - 네임스페이스는 프로그램 스크립트의 첫 번째 문장이어야 합니다 ?>
디렉토리와 파일과의 관계와 마찬가지로, PHP 네임스페이스도 계층적인 네임스페이스 이름을 지정할 수 있습니다. 따라서 네임스페이스 이름은 계층적인 방식으로 정의될 수 있습니다:
<?php namespace MyProject\Sub\Level; //层次적인 단일 네임스페이스를 선언합니다 const CONNECT_OK = 1; class Connection { /* ... */ } function Connect() { /* ... */ } ?>
위의 예제는 MyProject\Sub\Level\CONNECT_OK, MyProject\Sub\Level\Connection, MyProject\Sub\Level\Connect 함수를 생성합니다.
PHP 네임스페이스 내의 클래스 이름은 세 가지 방식으로 참조될 수 있습니다:
비정의된 이름 또는 프리픽스를 포함하지 않은 클래스 이름예를 들어 $a = new foo(); 또는 foo::staticmethod();. 현재 네임스페이스가 currentnamespace라면 foo는 currentnamespace\foo로 해석됩니다. foo를 사용하는 코드가 네임스페이스에 포함되지 않는 전체 코드라면 foo는 foo로 해석됩니다. 경고: 네임스페이스 내의 함수나 상수가 정의되지 않았을 경우, 비정의된 함수 이름이나 상수 이름은 전체 함수 이름이나 상수 이름으로 해석됩니다.
정의된 이름 또는 프리픽스를 포함한 이름예를 들어 $a = new subnamespace\foo(); 또는 subnamespace\foo::staticmethod();. 현재 네임스페이스가 currentnamespace라면 foo는 currentnamespace\subnamespace\foo로 해석됩니다. foo를 사용하는 코드가 네임스페이스에 포함되지 않는 전체 코드라면 foo는 subnamespace\foo로 해석됩니다.
완전 제한 이름 또는 전역 접두사 연산자를 포함한 이름예를 들어, $a = new \currentnamespace\foo(); 또는 \currentnamespace\foo::staticmethod();. 이 경우, foo는 항상 코드에서의 문자 이름(literal name)currentnamespace\foo로 해석됩니다.
아래는 이 세 가지 방법을 사용하는 예제입니다:
file1.php 파일 코드
<?php namespace Foo\Bar\subnamespace; const FOO = 1; function foo() {} class foo { static function staticmethod() {} } ?>
file2.php 파일 코드
<?php namespace Foo\Bar; include 'file1.php'; const FOO = 2; function foo() {} class foo { static function staticmethod() {} } /* 비제한 이름 */ foo(); // 함수로解析됩니다 Foo\Bar\foo foo::staticmethod(); // 클래스로解析됩니다 Foo\Bar\foo , 메서드는 staticmethod echo FOO; // 상수로解析됩니다 Foo\Bar\FOO /* 제한 이름 */ subnamespace\foo(); // 함수로解析됩니다 Foo\Bar\subnamespace\foo subnamespace\foo::staticmethod(); // 클래스로解析됩니다 Foo\Bar\subnamespace\foo, // 그리고 클래스 메서드 staticmethod echo subnamespace\FOO; // 상수로解析됩니다 Foo\Bar\subnamespace\FOO /* 완전 제한 이름 */ \Foo\Bar\foo(); // 함수로解析됩니다 Foo\Bar\foo \Foo\Bar\foo::staticmethod(); // 클래스로解析됩니다 Foo\Bar\foo, 그리고 클래스 메서드 staticmethod echo \Foo\Bar\FOO; // 상수로解析됩니다 Foo\Bar\FOO ?>
전역 클래스, 함수 또는 상수에 접근할 때, 완전 제한 이름을 사용할 수 있습니다. 예를 들어, \strlen() 또는 \Exception 또는 \INI_ALL.
명명 공간 내부에서 전역 클래스, 함수 및 상수에 접근합니다:
<?php namespace Foo; function strlen() {} const INI_ALL = 3; class Exception {} $a = \strlen('hi'); // 全局 함수 strlen 호출 $b = \INI_ALL; // 全局 상수 INI_ALL 접근 $c = new \Exception('error'); // 全局 클래스 Exception 예제화 ?>
PHP 네임스페이스의 구현은 언어 자체의 동적 특성에 영향을 받습니다. 따라서 아래의 코드를 네임스페이스로 변환할 때, 요소의 동적 접근을 사용해야 합니다.
example1.php 파일 코드:
<?php class classname { function __construct() { echo __METHOD__, '\n'; } } function funcname() { echo __FUNCTION__, '\n'; } const constname = 'global'; $a = 'classname'; $obj = new $a; // classname::__construct 출력 $b = 'funcname'; $b(); // funcname 출력 echo constant('constname'), '\n'; // global 출력 ?>
완전한限定 이름(네임스페이스 프리كس를 포함한 클래스 이름)을 사용해야 합니다. 주의, 동적 클래스 이름, 함수 이름, 상수 이름에서 완전한 이름과 제한 이름이 다를 때, 선두的反斜杠는 필요하지 않습니다.
네임스페이스 요소의 동적 접근
<?php namespace namespacename; class classname { function __construct() { echo __METHOD__, '\n'; } } function funcname() { echo __FUNCTION__, '\n'; } const constname = 'namespaced'; include 'example1.php'; $a = 'classname'; $obj = new $a; // 출력 classname::__construct $b = 'funcname'; $b(); // 함수 이름 출력 echo constant('constname'), '\n'; // 출력 global /* 따옴표를 사용하면, 사용 방법은 "\\namespacename\\classname"입니다;*/ $a = '\namespacename\classname'; $obj = new $a; // 출력 namespacename\classname::__construct $a = 'namespacename\classname'; $obj = new $a; // 출력 namespacename\classname::__construct $b = 'namespacename\funcname'; $b(); // namespacename\funcname 출력 $b = 'namespacename\funcname'; $b(); // namespacename\funcname 출력 constant('\namespacename\constname'), '\n' 출력 // namespaced 출력 constant('namespacename\constname'), '\n' 출력 // namespaced 출력 ?>
PHP는 현재 이름 공간 내부 요소에 접근하는 두 가지 추상적인 방법을 지원합니다. __NAMESPACE__ 마법 상수와 namespace 키워드.
상수 __NAMESPACE__의 값은 현재 이름 공간 이름을 포함하는 문자열입니다. 전역 코드에서는 이름 공간을 포함하지 않으며, 공백 문자열을 포함합니다.
__NAMESPACE__ 예제, 이름 공간 내의 코드
<?php namespace MyProject; '"', __NAMESPACE__, '"' 출력 // "MyProject" 출력 ?>
__NAMESPACE__ 예제, 전역 코드
<?php '"', __NAMESPACE__, '"' 출력 // "" 출력 ?>
동적으로 이름을 생성할 때 __NAMESPACE__ 상수가 매우 유용합니다.
__NAMESPACE__를 사용하여 이름을 동적으로 생성
<?php namespace MyProject; function get($classname) { $a = __NAMESPACE__ . '\\' . $classname; new $a 반환 } ?>
namespace 키워드는 현재 이름 공간 또는 자식 이름 공간의 요소를 명시적으로 접근하는 데 사용됩니다. 그것은 클래스 내의 self 연산자와 동일합니다.
namespace 연산자, 이름 공간 내의 코드
<?php namespace MyProject; blah\blah as mine 사용 // "Using namespaces: importing" 참조/"" aliasing blah\mine(); 호출 // function blah\blah\mine() 호출 namespace\blah\mine(); 호출 // function MyProject\blah\mine() 호출 namespace\func(); // function MyProject\func() 호출 namespace\sub\func(); // function MyProject\sub\func() 호출 namespace\cname::method(); // class MyProject\cname의 상태 메서드 "method" 호출 $a = new namespace\sub\cname(); // class MyProject\sub\cname의 객체를 인스턴스화합니다 $b = namespace\CONSTANT; // 상수 MyProject\CONSTANT의 값을 $b에 할당합니다 ?>
namespace 연산자, 전역 코드
<?php namespace\func(); // function func() 호출 namespace\sub\func(); // function sub\func() 호출 namespace\cname::method(); // class cname의 정적 메서드 "method" 호출 $a = new namespace\sub\cname(); // class sub\cname의 객체를 인스턴스화합니다 $b = namespace\CONSTANT; // 상수 CONSTANT의 값을 $b에 할당합니다 ?>
PHP 네임스페이스는 별칭이나 도입 방식을 두 가지 방식으로 지원합니다: 클래스 이름에 별칭 사용 또는 네임스페이스 이름에 별칭 사용.
PHP에서는 use 연산자를 통해 별칭을 구현합니다. 다음은 모든 가능한 세 가지 도입 방식의 예제입니다:
1、use 연산자를 통해 도입/별칭 사용
<?php namespace foo; use My\Full\Classname as Another; // 아래의 예제는 use My\Full\NSname as NSname와 동일합니다 use My\Full\NSname; // 전역 클래스를 도입합니다 use \ArrayObject; $obj = new namespace\Another; // foo\Another 객체를 인스턴스화합니다 $obj = new Another; // My\Full\Classname 객체를 인스턴스화합니다 NSname\subns\func(); // My\Full\NSname\subns\func 함수 호출 $a = new ArrayObject(array(1)); // ArrayObject 객체를 인스턴스화합니다 // "use \ArrayObject" 사용하지 않으면 foo\ArrayObject 객체를 인스턴스화합니다 ?>
2、一行에 여러 use 문 포함
<?php use My\Full\Classname as Another, My\Full\NSname; $obj = new Another; // My\Full\Classname 객체를 인스턴스화합니다 NSname\subns\func(); // My\Full\NSname\subns\func 함수 호출 ?>
导入操作은 컴파일 실행 중에 이루어지지만 동적 클래스 이름, 함수 이름 또는 상수 이름은 아닙니다.
3、导入 및 동적 이름
<?php use My\Full\Classname as Another, My\Full\NSname; $obj = new Another; // My\Full\Classname 객체를 인스턴스화합니다 $a = 'Another'; $obj = new $a; // Another 객체를 실제화 ?>
또한, import 작업은 비정의된 이름과 정의된 이름에 영향을 미칩니다. 완전 정의된 이름은 확정적이므로 영향을 받지 않습니다.
4、импорт과 полные имена
<?php use My\Full\Classname as Another, My\Full\NSname; $obj = new Another; // My\Full\Classname 클래스를 인스턴스화 $obj = new \Another; // Another 클래스를 인스턴스화 $obj = new Another\thing; // My\Full\Classname\thing 클래스를 인스턴스화 $obj = new \Another\thing; // Another\thing 클래스를 인스턴스화 ?>
이 이름공간에서, PHP가 비정의된 클래스, 함수 또는 상수 이름을 만나면, 그 이름을 해석하는 다른 우선순위 전략을 사용합니다. 클래스 이름은 항상 현재 이름공간의 이름으로 해석됩니다. 따라서 시스템 내부나 이름공간에 포함되지 않은 클래스 이름에 접근할 때는 완전 정의된 이름을 사용해야 합니다. 예를 들어:
1、이 이름공간에서 전역 클래스에 접근
<?php namespace A\B\C; class Exception extends \Exception {} $a = new Exception('hi'); // $a는 A\B\C\Exception 클래스의 객체입니다 $b = new \Exception('hi'); // $b는 Exception 클래스의 객체입니다 $c = new ArrayObject; // fatality error, A\B\C\ArrayObject class not found ?>
함수와 상수에 대해, 현재 이름공간에 해당 함수나 상수가 없다면, PHP는 전역 공간의 함수나 상수를 사용하도록 하여 사용합니다.
2、이 이름공간에서 대체 전역 함수/상수
<?php namespace A\B\C; const E_ERROR = 45; function strlen($str) { return \strlen($str); - 1; } echo E_ERROR, "\n"; // 출력 ""45" echo INI_ALL, "\n"; // 출력 ""7" - 전역 상수 INI_ALL 사용 echo strlen('hi'), "\n"; // 출력 ""1" if (is_array('hi')) { // 출력 "is not array" echo "is array\n"; } else { echo "is not array\n"; } ?>
이름 공간이 정의되지 않으면, 모든 클래스와 함수 정의는 전역 공간에 있습니다. PHP에서 이름 공간 개념을 도입하기 전과 동일합니다. 이름 앞에 프리퍼스 "\\"를 추가하여 이 이름이 전역 공간의 이름임을 나타냅니다. 이 이름이 다른 이름 공간에 위치해 있더라도 그렇습니다.
전역 공간 사용 설명
<?php namespace A\B\C; /* 이 함수는 A\B\C\fopen입니다 */ function fopen() { /* ... */ $f = \fopen(...); // 전역의 fopen 함수를 호출합니다 return $f; } ?>
이름 공간이 등장한 이후로 가장 쉽게 오류가 발생하는 것은 클래스 사용일 것입니다. 이 클래스의 검색 경로는 무엇인가요.
<?php namespace A; use B\D, C\E as F; // 함수 호출 foo(); // 먼저 이름 공간 "A"에서 정의된 함수 foo()를 호출하려고 시도합니다 // 다시 전역 함수 "foo"을 호출하려고 시도합니다 \foo(); // 전역 공간 함수 "foo"을 호출합니다 my\foo(); // 이름 공간 "A\my"에서 함수 "foo"을 호출합니다 F(); // 먼저 이름 공간 "A"에서 정의된 함수 "F"를 호출하려고 시도합니다 // 다시 전역 함수 "F"를 호출하려고 시도합니다 // 클래스 참조 new B(); // 이름 공간 "A"에서 정의된 클래스 "B"의 하나의 객체를 생성합니다 // 클래스 "A\B"를 찾지 못하면, 자동으로 클래스 "A\B"를 로드하려고 시도합니다 new D(); // 이도입 규칙을 사용하여 이름 공간 "B"에서 정의된 클래스 "D"의 하나의 객체를 생성합니다 // 클래스 "B\D"를 찾지 못하면, 자동으로 클래스 "B\D"를 로드하려고 시도합니다 new F(); // 이도입 규칙을 사용하여 이름 공간 "C"에서 정의된 클래스 "E"의 하나의 객체를 생성합니다 // 클래스 "C\E"를 찾지 못하면, 자동으로 클래스 "C\E"를 로드하려고 시도합니다 new \B(); // 전역 공간에서 정의된 클래스 "B"의 하나의 객체를 생성합니다 // 발견되지 않으면, 자동으로 클래스 "B"를 로드하려고 시도합니다 new \D(); // 전역 공간에서 정의된 클래스 "D"의 하나의 객체를 생성합니다 // 발견되지 않으면, 자동으로 클래스 "D"를 로드하려고 시도합니다 new \F(); // 전역 공간에서 정의된 클래스 "F"의 하나의 객체를 생성합니다 // 발견되지 않으면, 자동으로 클래스 "F"를 로드하려고 시도합니다 // 다른 이름 공간에서의 정적 메서드나 이름 공간 함수를 호출합니다 B\foo(); // 이름 공간 "A\B"에서 함수 "foo"을 호출합니다 B::foo(); // 네임스페이스 "A"에서 정의된 클래스 "B"의 "foo" 메서드를 호출합니다 // 클래스 "A\B"를 찾지 못하면, 자동으로 클래스 "A\B"를 로드하려고 시도합니다 D::foo(); // 이도입 규칙을 사용하여 이름 공간 "B"에서 정의된 클래스 "D"의 "foo" 메서드를 호출합니다 // 클래스 "B\D"가 찾지 못되면, 클래스 "B\D"를 자동으로 로드하려고 시도합니다 \B\foo(); // 네임스페이스 "B"에서 함수 "foo"을 호출합니다 \B::foo(); // 전역 공간에서 클래스 "B"의 "foo" 메서드를 호출합니다 // 클래스 "B"가 찾지 못되면, 클래스 "B"를 자동으로 로드하려고 시도합니다 // 현재 네임스페이스의 정적 메서드 또는 함수 A\B::foo(); // 네임스페이스 "A\A"에서 정의된 클래스 "B"의 "foo" 메서드를 호출합니다 // 클래스 "A\A\B"가 찾지 못되면, 클래스 "A\A\B"를 자동으로 로드하려고 시도합니다 \A\B::foo(); // 네임스페이스 "A"에서 정의된 클래스 "B"의 "foo" 메서드를 호출합니다 // 클래스 "A\B"가 찾지 못되면, 클래스 "A\B"를 자동으로 로드하려고 시도합니다 ?>
이름 해석은 다음과 같은 규칙을 따릅니다:
완전한 이름의 함수, 클래스, 상수에 대한 호출은 컴파일 시에 해석됩니다. 예를 들어 new \A\B 은 클래스로 해석됩니다 A\B。
모든 비정의 이름과 정의 이름(비완전한 이름)은 현재의导入 규칙에 따라 컴파일 시에 변환됩니다. 예를 들어 네임스페이스 A\B\C 는 변환됩니다 C그렇다면 C\D\e() 의 호출은 다음과 같이 변환됩니다 A\B\C\D\e()。
네임스페이스 내부에서 모든 입력 규칙에 따라 변환되지 않은 정의 이름은 현재 네임스페이스 이름 앞에 추가됩니다. 예를 들어 네임스페이스 A\B 내부 호출 C\D\e()그런 다음 C\D\e() 는 다음과 같이 변환됩니다 A\B\C\D\e() 。
비정의 클래스 이름은 현재의导入 규칙에 따라 컴파일 시에 변환됩니다(단명한导入 이름 대신 전체 이름을 사용합니다). 예를 들어 네임스페이스 A\B\C 导入로 C로 변환된다면, new C() 는 다음과 같이 변환됩니다 new A\B\C() 。
네임스페이스 내부(예를 들어 A\B)에서 비정의 이름의 함수 호출은 실행 시에 해석됩니다. 예를 들어 함수 foo() 의 호출은 다음과 같이 해석됩니다:
현재 네임스페이스에서 A\B\foo() 의 함수
찾고 호출하려고 시도합니다 전역(global) 네임스페이스 내의 함수 foo()。
네임스페이스(예를 들어A\B)내부에서 비정의 이름 또는 정의 이름 클래스(비완전한 이름)에 대한 호출은 실행 시에 해석됩니다. 다음은 호출 new C() 및 new D\E() 해석 과정: new C()해석: new D\E()해석: 전역 네임스페이스에서 전역 클래스를 참조하려면 완전한 이름을 사용해야 합니다 new \C()。
클래스 이름 앞에 현재 네임스페이스 이름을 추가하여 다음과 같이 됩니다:A\B\D\E그런 다음 해당 클래스를 찾습니다。
자동으로 클래스를 로드하려고 시도합니다 A\B\D\E。
현재 네임스페이스에서 찾습니다A\B\C클래스。
자동으로 클래스를 로드하려고 시도합니다A\B\C。