PHP 네임스페이스


네임스페이스란 무엇입니까?

넓게 말하면 네임스페이스는 사물을 캡슐화하는 방법입니다. 이 추상적인 개념은 여러 곳에서 찾아볼 수 있습니다.

예를 들어 운영체제에서 디렉토리는 관련 파일을 그룹화하는 데 사용되며, 디렉토리에 있는 파일은 네임스페이스 역할을 합니다.

예를 들어 foo.txt 파일은 /home/greg 및 /home/other 디렉터리에 동시에 존재할 수 있지만 두 개의 foo.txt 파일이 동일한 디렉터리에 존재할 수는 없습니다.

또한 /home/greg 디렉터리 외부에서 foo.txt 파일에 액세스할 때 /home/greg/foo.txt를 가져오려면 파일 이름 앞에 디렉터리 이름과 디렉터리 구분 기호를 넣어야 합니다. 이 원칙을 프로그래밍 분야에 적용한 것이 네임스페이스의 개념입니다.

PHP 네임스페이스(namespace)는 PHP 5.3에서 추가되었습니다. C#과 Java를 공부했다면 네임스페이스는 새로운 것이 아닙니다. 그러나 이는 PHP에서 여전히 매우 중요한 의미를 갖습니다.

PHP 네임스페이스의 역할

네임스페이스의 가장 명확한 목적 중 하나는 두 개의 함수 또는 클래스 이름이 중복되는 문제를 해결하는 것입니다. 동일한 이름이 나타나며, 그렇지 않으면 치명적인 오류가 발생합니다. 이런 경우에는 이름 중복만 피하면 해결이 됩니다. 가장 일반적인 방법은 접두사에 동의하는 것입니다.

PHP 네임스페이스는 다음 두 가지 유형의 문제를 해결할 수 있습니다.

1. 사용자가 작성한 코드와 PHP 내부 클래스/함수/상수 또는 타사 클래스/함수 / 상수 간의 이름 충돌.

2. 소스 코드의 가독성을 높이기 위해 매우 긴 식별자 이름(일반적으로 첫 번째 유형의 문제를 완화하기 위해 정의됨)에 대한 별칭(또는 짧은) 이름을 만듭니다.

PHP가 네임스페이스를 정의하는 방법

기본적으로 모든 상수, 클래스 및 함수 이름은 PHP 네임스페이스 지원과 마찬가지로 전역 공간에 배치됩니다. 이전과 동일합니다.

네임스페이스는 키워드 네임스페이스를 사용하여 선언됩니다. 파일에 네임스페이스가 포함되어 있으면 다른 모든 코드보다 먼저 네임스페이스를 선언해야 합니다. 구문 형식은 다음과 같습니다.

<?php  
// 定义代码在 'MyProject' 命名空间中  
namespace MyProject;  
// ... 代码 ...

동일한 파일에서 다음과 같이 다양한 네임스페이스 코드를 정의할 수도 있습니다.

<?php  
namespace MyProject1;  
// MyProject1 命名空间中的PHP代码  
namespace MyProject2;  
// MyProject2 命名空间中的PHP代码    
// 另一种语法
namespace MyProject3 {  
 // MyProject3 命名空间中的PHP代码    
}  
?>

네임스페이스를 선언하기 전에 유효한 코드는 정의하는 데 사용되는 코드입니다. 소스 파일 인코딩 선언문. 공백을 포함하여 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>” 会致命错误 - 命名空间必须是程序脚本的第一条语句
?>

Subnamespace

는 디렉터리 및 파일과 매우 유사합니다. , PHP 네임스페이스를 사용하면 계층적 네임스페이스 이름을 지정할 수도 있습니다. 따라서 네임스페이스 이름은 계층적 방식으로 정의할 수 있습니다.

<?php
namespace MyProject\Sub\Level;  //声明分层次的单个命名空间
const CONNECT_OK = 1;
class Connection { /* ... */ }
function Connect() { /* ... */  }
?>

위의 예에서는 상수 MyProjectSubLevelCONNECT_OK, MyProjectSubLevelConnection 클래스 및 MyProjectSubLevelConnect 함수를 만듭니다.

네임스페이스 사용량

PHP 네임스페이스의 클래스 이름은 다음 세 가지 방법으로 참조할 수 있습니다.

1. 정규화되지 않은 이름 또는 접두사가 없는 클래스 이름(예: $a=new foo() 또는 foo:: staticmethod()) ;. 현재 네임스페이스가 currentnamespace이면 foo는 currentnamespacefoo로 확인됩니다. foo를 사용하는 코드가 전역 코드이고 어떤 네임스페이스에도 코드를 포함하지 않는 경우 foo는 foo로 확인됩니다. 경고: 네임스페이스의 함수 또는 상수가 정의되지 않은 경우 정규화되지 않은 함수 또는 상수 이름은 전역 함수 또는 상수 이름으로 확인됩니다.

2. $a = new subnamespacefoo() 또는 subnamespacefoo::staticmethod();와 같이 정규화된 이름 또는 접두사가 포함된 이름입니다. 현재 네임스페이스가 currentnamespace이면 foo는 currentnamespacesubnamespacefoo로 확인됩니다. foo를 사용하는 코드가 전역 코드인 경우, 어떤 네임스페이스에도 포함되지 않은 코드인 foo는 subnamespacefoo로 확인됩니다.

3. 정규화된 이름 또는 전역 접두사 연산자가 포함된 이름(예: $a = new currentnamespacefoo(); 또는 currentnamespacefoo::staticmethod();) 이 경우 foo는 항상 코드에서 리터럴 이름 currentnamespacefoo로 확인됩니다.

다음은 이 세 가지 방법을 사용한 예입니다.

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 resolves to function Foo\Bar\foo
foo::staticmethod(); // 解析为类 Foo\Bar\foo的静态方法staticmethod。resolves to class Foo\Bar\foo, method staticmethod
echo FOO; // resolves to constant 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; // prints classname::__construct
$b = 'funcname';
$b(); // prints funcname
echo constant('constname'), "\n"; // prints 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; // prints classname::__construct
$b = 'funcname';
$b(); // prints funcname
echo constant('constname'), "\n"; // prints global
/* note that if using double quotes, "\namespacename\classname" must be used */
$a = '\namespacename\classname';
$obj = new $a; // prints namespacename\classname::__construct
$a = 'namespacename\classname';
$obj = new $a; // also prints namespacename\classname::__construct
$b = 'namespacename\funcname';
$b(); // prints namespacename\funcname
$b = '\namespacename\funcname';
$b(); // also prints namespacename\funcname
echo constant('\namespacename\constname'), "\n"; // prints namespaced
echo constant('namespacename\constname'), "\n"; // also prints namespaced
?>

네임스페이스 키워드 및 __NAMESPACE__ 상수

PHP는 두 가지 추상화를 지원합니다. 현재 네임스페이스, __NAMESPACE__ 매직 상수 및 네임스페이스 키워드.

상수 __NAMESPACE__의 값은 현재 네임스페이스의 이름을 포함하는 문자열입니다. 네임스페이스에 포함되지 않은 전역 코드에는 빈 문자열이 포함됩니다.

__NAMESPACE__ 예, 네임스페이스의 코드

<?php
namespace MyProject;
echo '"', __NAMESPACE__, '"'; // 输出 "MyProject"
?>
__NAMESPACE__ 示例,全局代码
<?php
echo '"', __NAMESPACE__, '"'; // 输出 ""
?>

상수 __NAMESPACE__는 이름을 동적으로 생성할 때 유용합니다. 예:

__NAMESPACE__를 사용하여 동적으로 이름 생성

<?php
namespace MyProject;
function get($classname)
{
    $a = __NAMESPACE__ . '\' . $classname;
    return new $a;
}
?>

키워드 네임스페이스를 사용하면 현재 네임스페이스나 하위 네임스페이스의 요소에 명시적으로 액세스할 수 있습니다. 클래스의 self 연산자와 동일합니다.

네임스페이스 연산자, 네임스페이스의 코드

<?php
namespace MyProject;
use blah\blah as mine; // see "Using namespaces: importing/aliasing"
blah\mine(); // calls function blah\blah\mine()
namespace\blah\mine(); // calls function MyProject\blah\mine()
namespace\func(); // calls function MyProject\func()
namespace\sub\func(); // calls function MyProject\sub\func()
namespace\cname::method(); // calls static method "method" of class MyProject\cname
$a = new namespace\sub\cname(); // instantiates object of class MyProject\sub\cname
$b = namespace\CONSTANT; // assigns value of constant MyProject\CONSTANT to $b
?>

네임스페이스 연산자, 전역 코드

<?php
namespace\func(); // calls function func()
namespace\sub\func(); // calls function sub\func()
namespace\cname::method(); // calls static method "method" of class cname
$a = new namespace\sub\cname(); // instantiates object of class sub\cname
$b = namespace\CONSTANT; // assigns value of constant CONSTANT to $b
?>

네임스페이스 사용: 별칭/가져오기

PHP 네임스페이스 지원에는 별칭 또는 가져오기를 사용하는 두 가지 방법이 있습니다. 클래스 이름에 별칭을 사용하거나 네임스페이스 이름을 사용하는 것입니다. 별칭. PHP는 가져온 함수나 상수를 지원하지 않습니다.

PHP에서 별칭은 연산자 사용을 통해 구현됩니다. 다음은 가능한 세 가지 가져오기 방법을 모두 사용하는 예입니다.

1 별칭을 가져오거나 사용하려면 사용 연산자를 사용하세요.

<?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 对象
?>

또한 가져오기 작업은 정규화되지 않은 이름과 정규화된 이름에만 영향을 미칩니다. 정규화된 이름은 결정적이므로 가져오기의 영향을 받지 않습니다.

4. 이름이 지정된 공간에서 가져오기 및 정규화된 이름

<?php
use My\Full\Classname as Another, My\Full\NSname;
$obj = new Another; // instantiates object of class My\Full\Classname
$obj = new \Another; // instantiates object of class Another
$obj = new Another\thing; // instantiates object of class My\Full\Classname\thing
$obj = new \Another\thing; // instantiates object of class 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; // 致命错误, 找不到 A\B\C\ArrayObject 类
?>

의 전역 클래스에 액세스합니다. 상수의 경우 함수나 상수가 현재 네임스페이스에 존재하지 않으면 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"
new D();    // 使用导入规则,创建命名空间 "B" 中定义的类 "D" 的一个对象
            // 如果未找到,则尝试自动装载类 "B\D"
new F();    // 使用导入规则,创建命名空间 "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" 中定义的类 "B" 的 "foo" 方法
              // 如果类 "A\B" 未找到,则尝试自动装载类 "A\B"
?>

이름 확인은 다음 규칙을 따릅니다.

1. 정규화된 이름을 가진 함수, 클래스 및 상수에 대한 호출은 컴파일 시 확인됩니다. 시간. 예를 들어 새 AB는 클래스 AB로 확인됩니다.

2. 모든 정규화되지 않은 이름과 정규화된 이름(완전히 정규화되지 않은 이름)은 현재 가져오기 규칙에 따라 컴파일 타임에 변환됩니다. 예를 들어 네임스페이스 ABC를 C로 가져온 경우 CDe()에 대한 호출은 ABCDe()로 변환됩니다.

3. 네임스페이스 내에서 가져오기 규칙에 따라 변환되지 않은 모든 정규화된 이름 앞에는 현재 네임스페이스 이름이 옵니다. 예를 들어, CDe()가 네임스페이스 AB 내에서 호출되면 CDe()는 ABCDe()로 변환됩니다.

4. 정규화되지 않은 클래스 이름은 현재 가져오기 규칙에 따라 컴파일 타임에 변환됩니다(짧은 가져오기 이름 대신 전체 이름이 사용됨). 예를 들어 네임스페이스 ABC를 C로 가져온 경우 new C()는 new ABC()로 변환됩니다.

5. 네임스페이스(예: AB) 내에서 정규화되지 않은 이름에 대한 함수 호출은 런타임에 해결됩니다. 예를 들어 foo() 함수에 대한 호출은 다음과 같이 구문 분석됩니다.

a. 현재 네임스페이스에서 ABfoo()라는 함수를 찾습니다.

b 전역 함수 foo를 찾아 호출해 봅니다. () 우주에서.

6. 네임스페이스(예: AB) 내의 정규화되지 않은 이름 또는 정규화된 이름 클래스(정규화되지 않은 이름)에 대한 호출은 런타임에 해결됩니다. new C()와 new DE()를 호출하는 파싱 과정은 다음과 같다. new C() 파싱: new DE() 파싱: 글로벌 네임스페이스에서 글로벌 클래스를 참조하기 위해 정규화된 이름인 new C()를 사용해야 합니다.

a. 클래스 이름 앞에 현재 네임스페이스 이름을 추가하여 ABDE가 되도록 한 다음 클래스를 검색합니다.

b. ABDE 클래스를 자동 로드해 보세요.

c. 현재 네임스페이스에서 클래스 ABC를 찾습니다.

d. ABC 클래스를 자동 로드해 보세요.