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 или сторонними классами/функциями/константами.

  • Создание.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

Как и的关系 с каталогами и файлами, 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

Имя класса в 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
?>

Ключевое слово namespace и константа __NAMESPACE__

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 имён:

  1. вызовы полных ограниченных имён функций, классов и констант происходят в время компиляции. Например      new \A\B пarsing в класс A\B

  2. Все неограниченные имена и ограниченные имена (не полные ограниченные имена) преобразуются в время компиляции по текущим правилам импорта. Например, если пространство имён     A\B\C импортируется как Cтогда вызовы C\D\e()     вызов будет converted в A\B\C\D\e()

  3. Внутри пространства имён, все неограниченные имена, не преобразованные по правилам импорта, добавляют текущее имя пространства имён перед ними. Например, в пространстве имён     A\B внутренние вызовы C\D\e()тогда C\D\e()     будет converted в A\B\C\D\e()

  4. неограниченные имена классов преобразуются в время компиляции (полное имя вместо короткого импорта). Например, если пространство имён     A\B\C импорт в C, то new C()     будет converted в new A\B\C()

  5. Внутри пространства имён (например A\B), вызовы неограниченных имён функций происходят в время выполнения. Например, вызов функции      foo() Такой вызов будет parsed:

    1. поиск по имени в текущем пространстве имён A\B\foo() функции

    2. попытка найти и вызвать глобальный (global) функции в пространстве имён foo()

  6. в пространстве имён (напримерA\Bвнутренние вызовы неограниченных или ограниченных имён классов (не полные ограниченные имена) происходят в время выполнения. Вот вызовы      new C() и new D\E() процесс parsing:       new C()пarsing: new D\E()пarsing: чтобы ссылаться на глобальный класс в глобальном пространстве имён, необходимо использовать полное ограниченное имя new \C()

    1. Добавление имени текущего пространства имён перед именем класса становится:A\B\D\Eи затем найти этот класс.

    2. попытка автоматической загрузки класса A\B\D\E

    3. поиск в текущем пространстве имёнA\B\Cкласс.

    4. попытка автоматической загрузки классаA\B\C