English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
PHP-назначное пространство (namespace) было добавлено в PHP 5.3. Если вы изучали C# и Java, то命名ное пространство не является чем-то новым. Но в PHP это все же имеет значительную важность.
PHP-назначное пространство решает следующие два типа проблем:
Конфликт имен между кодом пользователя и внутренними классами/функциями/константами PHP или сторонними классами/функциями/константами.
Создание.alias (или краткого) имени для очень длинных имен идентификаторов (обычно для решения первой проблемы класса проблем), что улучшает читаемость исходного кода.
По умолчанию, все константы, классы и имена функций располагаются в глобальном пространстве, как и до поддержки命名ных пространств в 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(); } ?>
Единственным законным кодом перед声明 namespace является команда declare для определения способа кодирования исходного файла. Все не PHP код, включая пробельные символы, не должны出现在 заявке namespace.
<?php declare(encoding='UTF-8'); // Определение нескольких namespace и кода, не содержащегося в namespace namespace MyProject { const CONNECT_OK = 1; class Connection { /* ... */ } function connect() { /* ... */ } } namespace { // Глобальный код session_start(); $a = MyProject\connect(); echo MyProject\Connection::start(); } ?>
Следующий код вызовет синтаксическую ошибку:
<html> <?php namespace MyProject; // Ошибка фатального характера, если перед namespace出现 «<html>» - namespace должен быть первым выражением в скрипте ?>
Как и的关系 с каталогами и файлами, namespace PHP также позволяет определять иерархические имена namespace. Поэтому, имя namespace может быть определено иерархически:
<?php namespace MyProject\Sub\Level; // Декларация иерархического единственного namespace const CONNECT_OK = 1; class Connection { /* ... */ } function Connect() { /* ... */ } ?>
Приведенный пример создает константу MyProject\Sub\Level\CONNECT_OK, класс MyProject\Sub\Level\Connection и функцию MyProject\Sub\Level\Connect.
Имя класса в namespace PHP можно ссылаться тремя способами:
Неопределенное имя, или имя класса без префиксаНапример, $a = new foo(); или foo::staticmethod();. Если текущий namespace является currentnamespace, foo будет интерпретирован как currentnamespace\foo. Если код, использующий foo, является глобальным и не содержится в каком-либо namespace, то foo будет интерпретирован как foo. Предупреждение: если функция или константа в namespace не определены, неопределенное имя функции или константы будет интерпретировано как имя глобальной функции или константы.
ограниченное имя, или имя, содержащее префиксНапример, $a = new subnamespace\foo(); или subnamespace\foo::staticmethod();. Если текущий namespace является currentnamespace, то foo будет парсится как currentnamespace\subnamespace\foo. Если код, использующий foo, является глобальным, не содержащимся в каком-либо namespace, 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"; // печать глобального ?>
необходимо использовать полное имя (включая имя класса с префиксом命名ного пространства). Обратите внимание, что в динамических именах классов, функций или констант полное имя и полное имя не различаются, поэтому префикс обратной косой черты не требуется.
динамический доступ к элементам命名空间
<?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 echo constant('\namespacename\constname'), '\n'; // Вывод namespaced echo constant('namespacename\constname'), '\n'; // Вывод namespaced ?>
PHP поддерживает два метода абстрактного доступа к элементам текущего пространства имен: магический константа __NAMESPACE__ и ключевое слово namespace.
Значение константы __NAMESPACE__ является строкой, содержащей имя текущего пространства имен. В глобальном контексте, не включенном в любое пространство имен, это пустая строка.
__NAMESPACE__ пример, код в пространстве имен
<?php namespace MyProject; echo '" ?>
__NAMESPACE__ пример, глобальный код
<?php echo '" ?>
Константа __NAMESPACE__ очень полезна при динамическом создании имен, например:
Использование __NAMESPACE__ для динамического создания имен
<?php namespace MyProject; function get($classname) { $a = __NAMESPACE__ . '\' . $classname; return new $a; } ?>
Ключевое слово namespace используется для явного доступа к элементам текущего или подназначения. Оно эквивалентно оператору self в классе.
namespace оператор, код в命名ном пространстве
<?php namespace MyProject; use blah\blah as mine; // see "Using namespaces: importing/aliasing" blah\mine(); // вызывается функция blah\blah\mine() namespace\blah\mine(); // вызывается функция MyProject\blah\mine() namespace\func(); // вызывается функция MyProject\func() namespace\sub\func(); // вызывается функция MyProject\sub\func() namespace\cname::method(); // вызывается статический метод "method" класса MyProject\cname $a = new namespace\sub\cname(); // создает объект класса MyProject\sub\cname $b = namespace\CONSTANT; //assigns value of constant MyProject\CONSTANT to $b ?>
namespace оператор, глобальный код
<?php namespace\func(); // вызывается функция func() namespace\sub\func(); // вызывается функция sub\func() namespace\cname::method(); // вызывается статический метод "method" класса cname $a = new namespace\sub\cname(); // создает объект класса sub\cname $b = namespace\CONSTANT; // Assigns value of constant CONSTANT to $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 ?>
Кроме того, операция импорта влияет только на неограниченные и ограниченные имена. Полное имя определено и не受到影响 импортом.
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, cannot find A\B\C\ArrayObject class ?>
Для функций и констант, если в текущем пространстве имен не существует этой функции или константы, 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"; } 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(); // Сначала пытаемся вызвать функцию "foo", определенную в пространстве имён "A" // Еще раз пытаемся вызвать глобальную функцию "foo" \foo(); // Вызов функции "foo" в глобальном пространстве имён my\foo(); // Вызов функции "foo" в пространстве имён "A\my" F(); // Сначала пытаемся вызвать функцию "F", определенную в пространстве имён "A" // Еще раз пытаемся вызвать глобальную функцию "F" // Ссылка на класс new B(); // Создание объекта класса "B", определенного в пространстве имён "A" // Если не найден, то пробуем автоматически загрузить класс "A\B" new D(); // Создание объекта класса "D", определенного в пространстве имён "B" // Если не найден, то пробуем автоматически загрузить класс "B\D" new F(); // Создание объекта класса "E", определенного в пространстве имён "C" // Если не найден, то пробуем автоматически загрузить класс "C\E" new \B(); // Создание объекта класса "B", определенного в глобальном пространстве имён // Если не найден, то пробуем автоматически загрузить класс "B" new \D(); // Создание объекта класса "D", определенного в глобальном пространстве имён // Если не найден, то пробуем автоматически загрузить класс "D" new \F(); // Создание объекта класса "F", определенного в глобальном пространстве имён // Если не найден, то пробуем автоматически загрузить класс "F" // Вызов статического метода или функции пространства имён из другого пространства имён B\foo(); // Вызов функции "foo" в пространстве имён "A\B" B::foo(); // Вызов метода "foo" класса "B", определенного в пространстве имён "A" // Если класс "A\B" не найден, то пробуем автоматически загрузить класс "A\B" D::foo(); // Использование правил импорта, вызов метода "foo" класса "D", определенного в пространстве имён "B" // Если класс "B\D" не найден, то попытка автоматической загрузки класса "B\D" \B\foo(); // Вызов функции "foo" в пространстве имён "B" \B::foo(); // Вызов метода "foo" класса "B" определенного в глобальном пространстве имён // Если класс "B" не найден, то попытка автоматической загрузки класса "B" // Статические методы или функции текущего пространства имён A\B::foo(); // Вызов метода "foo" класса "B" определенного в пространстве имён "A\A" // Если класс "A\A\B" не найден, то попытка автоматической загрузки класса "A\A\B" \A\B::foo(); // Вызов метода "foo" класса "B" определенного в пространстве имён "A" // Если класс "A\B" не найден, то попытка автоматической загрузки класса "A\B" ?>
правила parsing имён:
вызовы полных ограниченных имён функций, классов и констант происходят в время компиляции. Например new \A\B пarsing в класс A\B。
Все неограниченные имена и ограниченные имена (не полные ограниченные имена) преобразуются в время компиляции по текущим правилам импорта. Например, если пространство имён A\B\C импортируется как Cтогда вызовы C\D\e() вызов будет converted в A\B\C\D\e()。
Внутри пространства имён, все неограниченные имена, не преобразованные по правилам импорта, добавляют текущее имя пространства имён перед ними. Например, в пространстве имён A\B внутренние вызовы C\D\e()тогда C\D\e() будет converted в A\B\C\D\e() 。
неограниченные имена классов преобразуются в время компиляции (полное имя вместо короткого импорта). Например, если пространство имён A\B\C импорт в C, то new C() будет converted в new A\B\C() 。
Внутри пространства имён (например A\B), вызовы неограниченных имён функций происходят в время выполнения. Например, вызов функции foo() Такой вызов будет parsed:
поиск по имени в текущем пространстве имён A\B\foo() функции
попытка найти и вызвать глобальный (global) функции в пространстве имён foo()。
в пространстве имён (напримерA\Bвнутренние вызовы неограниченных или ограниченных имён классов (не полные ограниченные имена) происходят в время выполнения. Вот вызовы new C() и new D\E() процесс parsing: new C()пarsing: new D\E()пarsing: чтобы ссылаться на глобальный класс в глобальном пространстве имён, необходимо использовать полное ограниченное имя new \C()。
Добавление имени текущего пространства имён перед именем класса становится:A\B\D\Eи затем найти этот класс.
попытка автоматической загрузки класса A\B\D\E。
поиск в текущем пространстве имёнA\B\Cкласс.
попытка автоматической загрузки классаA\B\C。