English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

PHP 基础教程

PHP 高级教程

PHP & MySQL

PHP 参考手册

PHP 네임스페이스

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 출력
?>

namespace 키워드와 __NAMESPACE__ 상수

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"를 자동으로 로드하려고 시도합니다
?>

이름 해석은 다음과 같은 규칙을 따릅니다:

  1. 완전한 이름의 함수, 클래스, 상수에 대한 호출은 컴파일 시에 해석됩니다. 예를 들어      new \A\B 은 클래스로 해석됩니다 A\B

  2. 모든 비정의 이름과 정의 이름(비완전한 이름)은 현재의导入 규칙에 따라 컴파일 시에 변환됩니다. 예를 들어 네임스페이스     A\B\C 는 변환됩니다 C그렇다면 C\D\e()     의 호출은 다음과 같이 변환됩니다 A\B\C\D\e()

  3. 네임스페이스 내부에서 모든 입력 규칙에 따라 변환되지 않은 정의 이름은 현재 네임스페이스 이름 앞에 추가됩니다. 예를 들어 네임스페이스     A\B 내부 호출 C\D\e()그런 다음 C\D\e()     는 다음과 같이 변환됩니다 A\B\C\D\e()

  4. 비정의 클래스 이름은 현재의导入 규칙에 따라 컴파일 시에 변환됩니다(단명한导入 이름 대신 전체 이름을 사용합니다). 예를 들어 네임스페이스     A\B\C 导入로 C로 변환된다면, new C()     는 다음과 같이 변환됩니다 new A\B\C()

  5. 네임스페이스 내부(예를 들어 A\B)에서 비정의 이름의 함수 호출은 실행 시에 해석됩니다. 예를 들어 함수      foo() 의 호출은 다음과 같이 해석됩니다:

    1. 현재 네임스페이스에서 A\B\foo() 의 함수

    2. 찾고 호출하려고 시도합니다 전역(global) 네임스페이스 내의 함수 foo()

  6. 네임스페이스(예를 들어A\B)내부에서 비정의 이름 또는 정의 이름 클래스(비완전한 이름)에 대한 호출은 실행 시에 해석됩니다. 다음은 호출      new C()new D\E() 해석 과정:       new C()해석: new D\E()해석: 전역 네임스페이스에서 전역 클래스를 참조하려면 완전한 이름을 사용해야 합니다 new \C()

    1. 클래스 이름 앞에 현재 네임스페이스 이름을 추가하여 다음과 같이 됩니다:A\B\D\E그런 다음 해당 클래스를 찾습니다。

    2. 자동으로 클래스를 로드하려고 시도합니다 A\B\D\E

    3. 현재 네임스페이스에서 찾습니다A\B\C클래스。

    4. 자동으로 클래스를 로드하려고 시도합니다A\B\C