Как узнать namespace файла php

Обновлено: 03.07.2024

Чтобы понять как работают пространства имен мы начнем с того, что создаем и вызываем классы в глобальном пространстве имен:

Теперь добавим лишь одну строчку с указанием некоего пространства имен:

Теперь при вызове file_2.php получаем ошибку:

Причина, по которой мы получаем ошибку заключается в том, что в глобальнм пространстве имен уже нет класса UserClass.

Стоит отметить! Объявляя пространство имен в файле file_1.php мы обозначаем, что указанные ниже по коду классы, константы (указанные через ключевое слово const ) и функции будут доступны только в этом пространстве имен. Обычные переменные типа $var и константы, определенные через define() будут доступны глобально.

Чтобы обратиться к классу (или константе) нужно указать пространство имен, в котором он находится. Мы разберем несколько вариантов того, как это можно сделать.

Вариант 1: Указать пространсво имен непосредственно при вызове класса

Вариант 2: использовать оператор use для определения пространства имен для используемого класса

Вариант 2.1: Добавить псевданим с возможностью указать произвольное имя

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

Причина такого вопроса в том, что обозначая свое пространство имен мы перестаем иметь непосредственный контакт с глобальным пространством имен.

Для обращения к классу, функции или константе нам нужно указать обратный слэш перед их именем: \GlobalUserClass()

Благодаря вызову с обратным слэшом мы получили доступ к классы, находящемуся в глобальном пространстве имен

Вложенные зоны видимостимости. Есть ли такое?

Часто можно увидеть запись на подобии App\Category\Utilits\Awesome . Как стоит интерпретировать такую последовательность?

В PHP, в отличии от Python или Java, по историческим причинам нет строгой зависимости между пространствами имен и файловой структурой. Однако, следуя стандартам качества кода, разработчики следят за тем, чтобы пространства имен точно соответствовали названиям папок в файловой системе. Поэтому, такая вложенность означает, что исполняемый класс Awesome наверняка будет находиться в файле Awesome.php , который находится в папке App\Category\Utilits . Или (реже) — в папке App\Category будет найден файл Utilits.php , в котором расположен класс Awesome() . Но где находится папка App и называется ли она именно так — на этот вопрос сложнее ответить. Но чаще всего это какой-то интуитивно понятный корневой раздел проекта. Также подсказку можно найти в файле composer.json — там может быть указан алиас для корневого каталога.

Например в Laravel 6 (в тестовом проекте blog) мы можем увидеть строчку:

Это будет означать, что нужно заглануть в файл vendor\laravel\framework\src\Illuminate\Foundation\Auth\User.php

На этом все!

Пишите в комментариях нашли ли вы в этой заметки все ответы на свои вопросы по данной теме.

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

  1. Относительное имя файла, такое как foo.txt , преобразуемое в currentdirectory/foo.txt , где currentdirectory - текущая директория, в которой мы находимся. Тогда, если текущая директория /home/foo , то имя преобразуется в /home/foo/foo.txt .
  2. Относительное имя пути, такое как subdirectory/foo.txt , преобразуется в currentdirectory/subdirectory/foo.txt .
  3. Абсолютное имя пути, такое как /main/foo.txt , которое остаётся таким же: /main/foo.txt .
  1. Неполные имена (имена классов без префикса), такие как $a = new foo(); или foo::staticmethod(); . Если текущее пространство имён currentnamespace , то эти имена преобразуются в currentnamespace\foo . Если код находится в глобальном пространстве имён, то имена остаются такими же: foo . Предупреждение: неполные имена для функций и констант будут определяться в глобальном пространстве имён, если они не определены в текущем пространстве имён. Подробнее в Использование пространств имён: доступ к глобальным функциям и классам.
  2. Полные имена (имена классов с префиксами), такие как $a = new subnamespace\foo(); или subnamespace\foo::staticmethod(); . Если текущее пространство имён currentnamespace , то эти имена преобразуются в currentnamespace\subnamespace\foo . Если код находится в глобальном пространстве имён, то имена преобразуются в subnamespace\foo .
  3. Абсолютные имена или имена с предшествующим префиксом, обозначающим глобальное пространство. $a = new \currentnamespace\foo(); или \currentnamespace\foo::staticmethod(); . Имена всегда определяются так же, как и записаны: currentnamespace\foo .

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

<?php
namespace Foo \ Bar \ subnamespace ;

const FOO = 1 ;
function foo () <>
class foo
static function staticmethod () <>
>
?>

<?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
// c методом 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 был тернистым. Но к счастью она была добавлена к языку в версии PHP 5.3, и структура PHP кода значительно улучшилась с тех пор. Но как именно нам их использовать?

Что такое пространства имен?

«Не забывайте обратный слеш, когда Вы храните имя пространства имен в виде строки!»

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

Ранее разработчикам приходилось использовать префиксы с нижним подчеркиванием в своих классах, функциях и константах для разделения кода. Это эквивалентно тому, что каждый будет маркировать свои вещи и храниться они будут в одном большом ящике. Конечно, это по крайней мере хоть какая-то организации, но это очень неэффективно.

Пространства имен, помогут! Вы можете объявить одни и те же функцию, класс, интерфейс и определить константу в отдельных пространствах имен, не получая фатальных ошибок. По своей сути, пространство имен не более чем иерархически маркированные блоки кода содержащие обычный PHP код.

Вы используете их!

Важно понимать, что Вы косвенно используете пространства имен; Начиная с PHP 5.3, все определения, которые еще не объявлены в определенных пользователем пространствах имен, подпадают под глобальное пространство имен.

Глобальное пространство имен также хранит все внутренние определения PHP, такие как mysqli_connect() , и класс Exception . Поскольку глобальное пространство имен не имеет уникального идентифицирующего названия, его наиболее часто называют глобальное пространство.

Обратите внимание что использование пространства имен не является обязательным.
Ваш PHP скрипт будет прекрасно работать без них, и такое поведение не очень скоро изменится.

Определение пространства имен

Файл, содержащий пространство имен, должен содержать его объявление в начале перед любым другим кодом. Единственное что может объявляться перед пространством имен это зарезервированное слово declare , выражение declare может находиться перед объявлением пространства имен для указания кодировки файла.

Пространства имен объявляются с помощью зарезервированного слова namespace . Пространства имен подчиняются тем же правилам, что и другие идентификаторы в PHP. Таким образом, пространство имен должно начинаться с буквы или символа подчеркивания с последующим любым количеством букв, цифр или символов подчеркивания.


Если Вы хотите определить блок кода в глобальное пространство, можно использовать ключевое слово namespace , не добавляя имени.


Вы можете использовать несколько пространств имен в одном файле.


Вы также можете использовать одно и тоже пространство имен для нескольких разных файлов; процесс подключения файлов автоматически объединит их. Это хорошая практика кодирования, ограничить количество определений пространства имен до одного файла, так же, как Вы могли бы сделать это с классами.

Пространство имен используется, чтобы избежать противоречивых определений и ввести больше гибкости и организации в программный код.

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

Подпространства имен

Пространства имен могут следовать определенной иерархии, так же, как каталоги в файловой системе на компьютере. Подпространства имен чрезвычайно полезны для организации структуры проекта. Например, если ваш проект требует доступа к базе данных, Вы можете поместить код обработчика исключений базы данных и обработчика подключения в подпространство имен Database .

Для обеспечения гибкости, разумно хранить вложенные пространства имен в подкаталогах. Это способствует структурированию проекта и позволяет гораздо проще использовать его автозагрузчикам, которые следуют стандарту PSR-4.

PHP использует обратный слэш, в качестве разделителя пространства имен.

image

Интересный факт: в RFC, чтобы решить, какой разделитель пространства имен следует использовать, рассматривался вариант использования смайлика.


Вы можете использовать столько вложенных пространств имен, сколько хотите.


Определение подпространства имен с вложенными блоками кода не поддерживается. Следующий пример будет возвращать фатальную ошибку: «Объявления пространств имен не могут быть вложенными (Namespace declarations cannot be nested)».

Вызов кода из пространства имен

Если Вы хотите, создать новый экземпляр объекта, вызвать функцию или использовать константы из разных пространств имен, Вы используете обратный слэш. Существует три типа определений имени пространства имен:

Неполное имя

Это имя класса, функции или константы, не включающее в себя ссылку к какому бы то ни было пространству имён. Для тех, кто только начинает работать с пространством имен, это привычная точка зрения.

Полное имя

Так мы получаем доступ к иерархии подпространства имен; разделяется обратным слэшем.


Пример ниже возвратит фатальную ошибку: «Fatal error: Class 'MyProject\Database\MyProject\FileAccess\Input' not found», потому что MyProject\FileAccess\Input не имеет отношения к пространству имен в котором Вы находитесь.

Абсолютное имя

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

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


Нам не обязательно использовать полное имя для внутренних функций PHP. Неполные имена для функций и констант будут определяться в глобальном пространстве имен, если они не определены в текущем пространстве имен.

Зная это, мы можем теперь перегружать внутренние функции PHP, при этом имея возможность вызвать первоначальную функцию (или константу).

Динамические вызовы

PHP — динамический язык программирования; так что Вы можете применять этот функционал для вызова кода из пространства имён. Это, по существу тоже, что использование динамического имени класса или подключение динамического файла используя переменную для хранения его имени. Разделитель имен PHP использует те же метасимволы в строках. Не забывайте про обратный слеш, когда Вы храните имя пространства имен в виде строки!

Ключевое слово namespace

Ключевое слово namespace используется не только для определения пространства имен, оно также может быть использован для вызова в текущем пространстве имен, функционально аналогичный ключевому слову self для классов.

Константа __NAMESPACE__

Так же как ключевое слово self не может быть использовано для определения имени текущего класса, также и ключевое слово namespace не может использоваться для текущего пространства имен. Поэтому мы используем константу __NAMESPACE__


Эта константа является весьма полезной в начале изучения пространства имен; также она очень полезна при отладке. Так как это строка, она может быть использована в сочетании с динамическими вызовами кода, рассмотренные выше.

Импорт или создание псевдонима имени

Важная особенность пространств имен в PHP — это возможность ссылаться на внешнее абсолютное имя по псевдониму, или импортирование.

Импорт является очень полезным и фундаментальным аспектом пространства имен. Это дает вам возможность использовать внешние пакеты, например, библиотеки, не беспокоясь о конфликте имен. Импорт осуществляется с помощью ключевого слова use . При желании, Вы можете указать пользовательский псевдоним с помощью ключевого слова as .

Как это использовать

Абсолютное имя может быть привязаны к более короткому неполному имени, так что вам не придется писать его абсолютное имя каждый раз, когда Вы хотите его использовать. Создание псевдонима или импорт должны происходить в родительском пространстве имен или в глобальном. Попытка сделать это в рамках метода или функции является недопустимым синтаксисом (invalid syntax).


Альтернативой, является возможность присвоения псевдонима с другим именем


Вы также можете импортировать такие глобальные классы, как Exception. При импорте, вам не придется писать его абсолютное имя.

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


Хотя есть поддержка динамического вызова пространства имен, динамический импорт не поддерживается.

Работая со сложными сценариями, может возникнуть ситуация, когда при инициализации переменной или функции возникает непреднамеренное дублирование имен, что нарушит ход компиляции скрипта и выдаст ошибку. В этом уроке мы рассмотрим выжное понятие в PHP – пространства имен, применяя которое мы избавимся о ошибкок, связанных с дублированием имен в вашем сценарии.

Пространства имен в PHP

Пространства имен — это квалификаторы, которые решают две разные проблемы:

  • Позволяют использовать одно и то же имя для более чем одного класса и предотвратить конфликт имен между вашим кодом и сторонним.
  • Пространства имен могут сделать наш код более организованным, группируя классы, которые работают вместе для выполнения задачи.

Если мы попытаемся определить две разные функции, но с одинаковыми именами, то PHP выдаст ошибку во время запуска кода. Проблема этого ограничения в том, что если вы используете чью-либо стороннюю библиотеку, предоставляющую класс например, с именем User , то вы не можете создать свой собственный класс с таким же именем.

Пространства имен позволяют нам обойти эту проблему, и мы можем создать столько классов User , сколько нам понадобится. Кроме того пространства имен позволят нам организовать код в удобные пакеты, а также обозначить свои права владения этим кодом.

Пространства имен и файловая структура

Концепция определения и вызова пространств имен аналогична обычной файловой структуре в наших операционных системах.

Представьте, что пространства имен — это папки, а файлы — классы:

  • В папке /base/math может быть несколько файлов: numbers.php , calcul.php и так далее. Но не может быть двух файлов с одинаковым именем.
  • Для доступа к numbers.php из файла calcul.php , вы можете напрямую обратиться к numbers.php
  • В папке /base/mechanic также может быть несколько файлов: physics.php , electro.php и т.д. И здесь же у вас может быть файл numbers.php , даже если файл с этим именем существует в папке /base/math .
  • Внутри папки /mechanic для доступа к numbers.php вы будете ссылаться /base/mechanic/numbers.php
  • Внутри папки /mechanic , если вам нужно было сослаться на файл numbers.php , который находится в папке /base/ math , вам нужно будет использовать /base/math/numbers.php

Точно так же работает пространства имен.

Объявление пространства имен

Пространство имён задается с помощью ключевого слова namespace , за которым следует имя пространства имён:

Синтаксис

Примечание: Декларация namespace должна прописываться в первой строке сценария сразу после <?php (за исключением ключевого слова declare ). В противном случае ваш код будет недействительным.

Если мы добавим объявление пространства имен в начало файла PHP, все классы, функции и константы будут элементами этого пространства имен.

Создадим файл с именем Math.php и добавим следующий код:

Пример

  • Сначала мы объявляем пространство имен — namespace Math;. (Теперь, все классы, интерфейсы, константы и функции будут элементами этого пространства имен)
  • Затем мы объявили функцию add().
  • Затем константа класса PI.
  • Затем класс Geometry.

Использование пространств имен

Следующим шагом создадим еще один файл с именем usage.php и получим доступ к элементам указанного выше пространства имен Math (функциям, константам и классам).

Пример

Примечание: Символ \ используется для перехода на уровень ниже в пространствах имен.

Когда одновременно используются несколько классов из одного и того же пространства имен, проще использовать ключевое слово namespace , чтобы не прописывать каждый раз квалификатор Math\ .

В следующем примере мы получим доступ к элементам указанного выше пространства имен Math без квалификатора Math\ :

Пример

Подпространства имен

В операционной системе папки внутри могут содержать другие папки. Таким же образом пространства имен могут содержать пространства имен. Они называются подпространствами имен.

Пример

В следующем примере мы создадим пространство имен с именем Math , а также добавим в него подпространства имен и классы:

  • Создадим основное пространство имен: Math
  • Добавим одно подпространство имен: Math\Geometry (для обработки геометрии)
  • Создадим два класса: Math\Constants (для сохранения часто используемых констант) и Math\Geometry\Circle (для вычисления диаметра, площади, длины окружности)

Вот окончательная структура нашего проекта:

Math/Constants.php

Пример

Math/Geometry/Circle.php

Пример

Примечание:

В файле Circle.php мы прописали \Math\Constants::PI ссылаясь на константу в файле Constants.php . Это потому, что сценарий PHP выполняется всегда относительно текущего пространства имен. Когда пространство имен начинается с обратной косой черты ( \ ), то путь к имени элемента будет исчисляться относительно глобального пространства имен.

  • Если бы мы просто прописали Constants::PI в файле Circle.php , то ссылка была бы ткой \Math\Geometry\ Constants::PI .
  • Если бы мы использовали Math\Constants::PI (без обратной косой черты \ ) в файле Circle.php , то получили бы ссылку \Math\Geometry\ Math\Constants::PI

Наконец, давайте используем наши классы в файле index.php , который должен находиться в корневой папке вашего проекта:

Пример

В примере выше мы первым делом включили файлы классов Constants.php и Circle.php . Затем использовал класс Math\Geometry\Circle и его методы.

Важно отметить, что index.php автоматически будет находиться в глобальном пространстве имен, так как мы не указали для него не одного из пространств имен.

Импортирование пространств имен

Если в нашем проекте предусмотрена иерархия пространств имен, мы можем импортировать интересующее нас пространство имен в тот или иной файл, используя ключевое слово use .

Если вы добавите следующий код в свой index.php , класс Math\Geometry\Circle будет импортирован в текущую область:

Пример

Вы можете импортировать как пространства имен, так и классы:

Если при запуске PHP скрипта будут два класса с одинаковыми именами, то они вступят в конфликт, что приведет к фатальной ошибке. Это на самом деле не очень удобно, так как постоянно приходится следить за уникальностью имен.

Для примера рассмотрим следующую ситуацию: у вас есть сайт, на котором есть пользователи и админ. При этом в папке users хранятся классы для юзеров, а в папке admin - классы для админа.

Пусть и для юзеров, и для админа нужен некий класс Page , отвечающий за какие-то страницы сайта. При этом для юзеров будет свой класс, а для админа - свой. В таком случае нас и поджидает конфликт имен.

Самый простой способ решения этого конфликта - дать отличающиеся имена классам, например, UsersPage и AdminPage . Этот путь, однако, постепенно ведет к появлению очень длинных имен классов.

В PHP существует и другой путь решения проблемы - пространства имен. Суть в следующем: каждый класс может относится к какому-то пространству имен и при этом уникальность имен классов должна соблюдаться только внутри этого пространства.

То есть, для решения нашей проблемы мы можем сделать следующее: отнести один класс Page к какому-нибудь пространству имен, например, Users , а второй класс Page отнести к другому пространству имен, например, Admin .

Синтаксис пространств имен

Чтобы задать классу пространство имен, нужно первой строчкой файла, в котом хранится этот класс написать команду namespace , а после нее через пробел - название этого пространства.

Если класс относится к какому-нибудь пространству имен, то для создания объекта класса нужно будет указать не только имя класса, но и его пространство имен, разделенные обратным слешем. Давайте посмотрим на примере.

Пусть у нас есть класс Page , не относящийся ни к какому пространству имен. Тогда объект этого класса мы создадим следующим образом:

Пусть теперь этот класс принадлежит пространству имен Admin . В этом случае объект этого класса мы будем создавать уже вот таким образом:

Посмотрим на примере

Давайте разнесем классы для юзеров и классы для админа по разным пространствам имен, чтобы избежать описанных выше конфликтов классов.

Для класса Page из файла /admin/page.php укажем пространство имен Admin :

А для класса Page из файла /users/page.php укажем пространство имен Users :

Давайте теперь в файле /index.php создадим объект одного и второго класса Page :

<?php require_once '/admin/page.php'; require_once '/users/page.php'; $adminPage = new \Admin\Page; $usersPage = new \Users\Page; ?>

Пусть у вас есть папка core и папка project . В каждой из папок есть свой класс Controller . Сделайте так, чтобы эти классы принадлежали разным пространствам имен. В файле index.php создайте объекты одного и второго классов.

Подпространства имен

Пусть теперь у нас есть более сложная ситуация: для админа нужно сделать два класса Page - один с данными страницы, а второй - с представлением этих данных. Пусть первый класс находится в файле /admin/data/page.php , а второй - в файле /admin/view/page.php .

Выше мы уже решили, что все классы из папки admin будут относится к пространству имен Admin . Однако, теперь в этом самом пространстве у нас конфликт двух классов. Для решения проблемы можно сделать дополнительные подпространства имен. Например, можно сделать пространство имен Admin , а в нем подпространства Data и View . В таком случае имена этих подпространств просто записываются через обратный слеш - как при задании пространства имен, так и при создании объекта класса.

Здесь следует уточнить, что уровень вложенности подпространств не ограничен (можно создавать под под пространства в подпространствах и так далее).

Итак, давайте доделаем наш описанный выше пример. Для класса Page из файла /admin/data/page.php укажем пространство имен Admin\Data :

Для класса Page из файла /admin/view/page.php укажем пространство имен Admin\View :

Создадим объекты наших классов:

<?php require_once '/admin/data/page.php'; require_once '/admin/view/page.php'; $adminDataPage = new \Admin\Data\Page; $adminViewPage = new \Admin\View\Page; ?>

Пусть у вас есть папка modules/cart . Сделайте так, чтобы все классы из этой папки относились к пространству имен Modules\Cart .

Пусть у вас есть папка modules/shop/cart/ . Сделайте так, чтобы все классы из этой папки относились к пространству имен Modules\Shop\Cart .

Некоторые замечания

В примерах выше имена пространств имен совпадают с именами папок, в которых хранятся файлы. Делать так - хорошая практика, но обязательным это не является.

Читайте также: