Часто задаваемые вопросы (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, ZEND_THREAD_SAFE или ZEND_DEBUG_BUILD

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

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

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

<?php
$a
= new \stdClass;
?>

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

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

<?php
$a
= new stdClass;
?>

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

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

<?php
namespace foo;
$a = new \stdClass;

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

$a = \DirectoryIterator::CURRENT_AS_FILEINFO;

// расширение внутреннего или глобального класса
class MyException extends \Exception {}
?>

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

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

<?php
namespace foo;

class
MyClass {}

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

// расширение класса из текущего пространства имён
class Extended extends MyClass {}

// доступ к глобальной функции
$a = \globalfunc();

// доступ к глобальной константе
$b = \INI_ALL;
?>

Как такое имя как \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 в my\name.

В ином случае, текущее имя пространства имён становится префиксом к 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 другого имени, то применяется этот синоним.

В ином случае, текущее имя пространства имён становится префиксом к 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() {}
function
foo() {}
function
sort(&$a)
{
\sort($a); // вызывает глобальную функцию "sort"
$a = array_flip($a);
return
$a;
}

my(); // вызывает "foo\my"
$a = strlen('hi'); // вызывает глобальную функцию "strlen", потому что "foo\strlen" не существует
$arr = array(1,3,2);
$b = sort($arr); // вызывает функцию "foo\sort"
$c = foo(); // вызывает функцию "foo\foo" - импорт не применяется

$a = FOO; // присваивает переменной $a значение константы "foo\FOO" - импорт не применяется
$b = INI_ALL; // присваивает переменной $b значение глобальной константы "INI_ALL"
?>

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

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

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, ZEND_THREAD_SAFE или ZEND_DEBUG_BUILD

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

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

<?php
namespace bar;
const
NULL = 0; // Фатальная ошибка;
const true = 'stupid'; // также фатальная ошибка;
// и т.д.
?>