## Часто задаваемые вопросы (FAQ): что нужно знать о пространствах имён

(PHP 5 >= 5.3.0, PHP 7, PHP 8)

Этот список вопросов разделён на две части: общие вопросы и некоторые особенности реализации, которые полезны для полного понимания.

Вначале общие вопросы.

1. Если в коде не указаны пространства имён, нужно ли считать что-либо из этого важным?
2. Как обращаться к внутренним или глобальным классам в пространстве имён?
3. Как обращаться к функциям классов в пространствах имён, или константам в их пространстве имён?
4. Как разрешаются имена `\my\name` или `\name`?
5. Как разрешается имя `my\name`?
6. Как разрешается неполное имя класса `name`?
7. Как разрешается неполное имя функции или неполное имя константы наподобие `name`?

Некоторые детали реализации пространств имён, которые полезно понимать.

1. Импортируемые имена не должны конфликтовать с классами, определёнными в том же файле.
2. Вложенные пространства имён недопустимы.
3. Динамические имена пространств имён (идентификаторы, взятые в кавычки) должны экранировать символ обратного слеша.
4. Ссылаться на неопределённые константы, используя обратный слеш, нельзя. Выводится фатальная ошибка
5. Невозможно переопределить специальные константы `null`, `true` или `false`

### Если в коде не указаны пространства имён, нужно ли считать что-либо из этого важным?

Нет, пространства имён не влияют ни на тот код, который уже написали, ни на ещё ненаписанный код без пространств имён. Разрешается писать такой код, если нужно:

Пример #1 Доступ к глобальным классам вне пространства имён

    <?php
    $a = new \stdClass;
    print $a::class;

Функционально это эквивалентно следующему:

Пример #2 Доступ к глобальным классам вне пространства имён

    <?php
    $a = new stdClass;
    print $a::class;

### Как обращаться к внутренним или глобальным классам в пространстве имён?

Пример #3 Доступ ко внутренним классам в пространствах имён

    <?php

    namespace foo;
    $a = new \stdClass;
    print $a::class . "\n";

    function test(?\ArrayObject $parameter_type_example = null) {}

    $a = \FilesystemIterator::CURRENT_AS_FILEINFO;
    print $a . "\n";

    // Расширение внутреннего или глобального класса
    class MyException extends \Exception {}
    print MyException::class . "\n";

### Как использовать функции классов в пространствах имён или константы в их собственном пространстве имён?

Пример #4 Доступ ко внутренним классам, функциям или константам в пространствах имён

    <?php

    namespace foo;

    class MyClass {}

    // Определение класса текущего пространства имён в качестве типа параметра
    function test(?MyClass $parameter_type_example = null) {}
    // Другой способ определить класс из текущего пространства имён в качестве типа параметра
    function test2(?\foo\MyClass $parameter_type_example = null) {}

    // Расширение класса из текущего пространства имён
    class Extended extends MyClass {}
    print Extended::class . "\n";

    // Доступ к глобальной функции
    $a = \strlen("test");
    print $a . "\n";

    // Доступ к глобальной константе
    $b = \INI_ALL;
    print $b . "\n";

### Как разрешаются имена наподобие `\my\name` или `\name`?

Имена, которые начинаются с обратного слеша `\`, разрешаются в названия, на которые сами похожи, поэтому имя `\my\name` разрешается в название `my\name`, а имя `\Exception` — в `Exception`.

Пример #5 Абсолютные имена

    <?php

    namespace foo;

    $a = new \my\name(); // Создаёт экземпляр класса my\name
    echo \strlen('hi'); // Вызывает функцию strlen
    $a = \INI_ALL; // Переменной $a присваивается значение константы INI_ALL

### Как разрешается имя `my\name`?

Имена наподобие `my\name`, — которые содержат обратный слеш, но не начинаются с него, — разрешаются двумя способами.

Уровень `my` в имени `my\name` заменяется псевдонимом, если уровню `my` присвоили псевдоним с другим именем, которое импортировали инструкцией use.

В остальных случаях перед именем `my\name` добавляется название текущего пространства имён.

Пример #6 Полные имена

    <?php

    namespace foo;

    use blah\blah as foo;

    $a = new my\name(); // Создаёт экземпляр класса foo\my\name
    foo\bar::name(); // Вызывает статический метод name, который определили в классе blah\blah\bar
    my\bar(); // Вызывает функцию foo\my\bar
    $a = my\BAR; // Присваивает переменной $a значение константы foo\my\BAR

### Как разрешается неполное имя класса вроде `name`?

Названия классов наподобие `name`, — которые не содержат обратного слеша, — разрешаются двумя способами.

Название класса заменяется псевдонимом, если имени `name` присвоили псевдоним с другим именем, которое импортировали инструкцией use.

В остальных случаях к имени `name` добавляется текущее название пространства имён.

Пример #7 Неполные имена классов

    <?php

    namespace foo;

    use blah\blah as foo;

    $a = new name(); // Создаёт экземпляр класса foo\name
    foo::name(); // Вызывает статический метод name, который определили в классе blah\blah

### Как разрешается неполное название функции или неполное имя константы вроде `name`?

Названия функций или констант наподобие `name`, — которые не содержат обратного слеша, — разрешаются двумя способами.

Вначале перед именем `name` добавляется текущее название пространства имён.

Затем, если текущее пространство имён не содержит названия константы или функции с именем `name`, вызывается глобальная константа или функция с названием `name`, если константу или функцию с таким названием определили в глобальном пространстве имён.

Пример #8 Неполные имена функций или констант

    <?php

    namespace foo;

    use blah\blah as foo;

    const FOO = 1;

    function my() {
        print __FUNCTION__ . "\n";
    }
    function foo() {
        print __FUNCTION__ . "\n";
    }
    function sort(&$a)
    {
        \sort($a); // Вызывает глобальную функцию sort
        $a = array_flip($a);
        return $a;
    }

    my(); // вызывает функцию foo\my
    print strlen('hi') . "\n"; // Вызывает глобальную функцию strlen, потому что функцию foo\strlen не определили
    $arr = array(1,3,2);
    $b = sort($arr); // Вызывает функцию foo\sort
    var_dump($b);
    foo(); // Вызывает функцию foo\foo, без импорта

    $a = FOO; // Присваивает переменной $a значение константы foo\FOO, без импорта
    print $a;
    $b = INI_ALL; // Присваивает переменной $b значение глобальной константы INI_ALL
    print $b;

### Импортируемым именам нельзя конфликтовать с классами, которые определили в том же файле

Следующие комбинации скриптов допустимы:

file1.php

    <?php

    namespace my\stuff;

    class MyClass {}

another.php

    <?php

    namespace another;

    class thing {}

file2.php

    <?php

    namespace my\stuff;

    include 'file1.php';
    include 'another.php';

    use another\thing as MyClass;
    $a = new MyClass; // Создаёт экземпляр класса thing из пространства имён another

Конфликт имён отсутствует, даже несмотря на то что класс `MyClass` существует внутри пространства имён `my\stuff`, потому что определение MyClass находится в отдельном файле. Однако следующий пример приводит к фатальной ошибке с конфликтом имён, потому что класс MyClass определён в том же файле, в котором указано ключевое слово use.

    <?php

    namespace my\stuff;

    use another\thing as MyClass;

    class MyClass {} // Фатальная ошибка: MyClass конфликтует с выражением импорта
    $a = new MyClass();

### Вложенные пространства имён недопустимы.

PHP не разрешает вложение пространств имён

    <?php

    namespace my\stuff {
        namespace nested {
            class foo {}
        }
    }

Однако сымитировать вложенные пространства имён можно так:

    <?php

    namespace my\stuff\nested {
        class foo {}
    }

### Динамические имена пространств имён (идентификаторы, взятые в кавычки) должны экранировать символ обратного слеша.

Важно понимать это, потому что обратный слеш внутри строк работает как экранирующий символ. Он должен быть продублирован, когда указан внутри строки, иначе появляется риск неумышленных последствий:

Пример #9 Подводные камни при указании имени пространства имён внутри строки с двойными кавычками

    <?php

    $a = "dangerous\name"; // Символ \n — переход на новую строку внутри строки с двойными кавычками!
    $obj = new $a;

    $a = 'not\at\all\dangerous'; // А тут нет проблем.
    $obj = new $a();

Внутри строк, заключённых в одинарные кавычки, обратный слеш в качестве разделителя более безопасен, но по-прежнему лучше рекомендуемая практика экранирования обратного слеша во всех строках.

### Ссылаться на неопределённые константы, используя обратный слеш, нельзя. Выводится фатальная ошибка

Любая неопределённая константа — неполное имя наподобие `FOO` — будет приводить к выводу сообщения о том, что PHP предположил, что `FOO` было значением константы. Любая константа, с полным или абсолютным именем, которая содержит символ обратного слеша, будет приводить к фатальной ошибке, если не будет найдена.

Пример #10 Неопределённые константы

    <?php

    namespace bar;

    $a = FOO; // Выводит предупреждение: undefined constants "FOO" assumed "FOO";
    $a = \FOO; // Фатальная ошибка: undefined namespace constant FOO
    $a = Bar\FOO; // Фатальная ошибка: undefined namespace constant bar\Bar\FOO
    $a = \Bar\FOO; // Фатальная ошибка: undefined namespace constant Bar\FOO

### Невозможно переопределить специальные константы `null`, `true` или `false`

Любая попытка определить константу пространства имён, которая совпадает с названиями специальных встроенных констант, приведёт к фатальной ошибке.

Пример #11 Неопределённые константы

    <?php

    namespace bar;

    const NULL = 0; // Фатальная ошибка;
    const true = 'stupid'; // Тоже фатальная ошибка;
    // и т. д.

`↑` and `↓` to navigate • `Enter` to select • `Esc` to close • `/` to open