Пространства имён PHP
Пространства имён PHP — способ группировки классов, функций и констант в логическую структуру для предотвращения конфликтов имён.
Пространство имён — это способ объединить связанные классы, интерфейсы, функции и константы под одним логическим именем. Представьте это как папки на диске: два файла с именем index.php могут сосуществовать, если находятся в разных папках. Точно так же два класса с именем User могут сосуществовать, если находятся в разных пространствах имён.
Без пространств имён все имена живут в одном общем глобальном пространстве. Как только ваш проект и сторонняя библиотека одновременно объявляют класс с именем Logger или Router, PHP выбрасывает фатальную ошибку Cannot declare class. Пространства имён — стандартное решение этой проблемы, и они лежат в основе автозагрузки Composer (стандарт PSR-4), которую использует практически каждый современный PHP-пакет.
Зачем нужны пространства имён
- Избежание конфликтов имён. Два фрагмента кода могут использовать одно и то же имя класса или функции, если они находятся в разных пространствах имён — ваш код никогда не столкнётся с кодом библиотеки.
- Организация больших кодовых баз. Пространства имён отражают структуру папок, делая очевидным местонахождение класса (
App\Service\Mailerнаходится вapp/Service/Mailer.php). - Обеспечение автозагрузки. PSR-4 сопоставляет префикс пространства имён с каталогом, поэтому Composer может загружать классы по требованию без ручных операторов
require.
Объявление пространства имён
Пространство имён объявляется с помощью ключевого слова namespace. Оно должно быть самым первым оператором в файле (перед ним может стоять только строка declare(strict_types=1)). Уровни имён разделяются обратным слешем (\):
<?php
namespace App\Service;
class Mailer
{
public function send(string $to): string
{
return "Mail sent to {$to}";
}
}Всё, объявленное ниже строки namespace — класс Mailer — теперь находится в App\Service. Его полное имя — App\Service\Mailer.
Обращение к элементам пространства имён
Существует три способа обратиться к имени из другого пространства имён.
Полностью квалифицированное имя начинается с ведущего \ и называет элемент от глобального корня — оно однозначно везде:
<?php
$mailer = new \App\Service\Mailer();Квалифицированное имя является относительным к текущему пространству имён, поэтому Service\Mailer внутри пространства имён App разрешается в App\Service\Mailer. Имя без обратного слеша является неквалифицированным и ищется сначала в текущем пространстве имён.
Импорт с помощью use
Писать полный путь каждый раз утомительно. Ключевое слово use импортирует имя в текущий файл, чтобы вы могли обращаться к нему по короткому имени:
<?php
use App\Service\Mailer;
$mailer = new Mailer(); // resolves to App\Service\MailerПсевдонимы с помощью as
Когда два импортированных класса имеют одинаковое короткое имя, задайте одному псевдоним с помощью as для устранения неоднозначности:
<?php
use App\Service\Mailer;
use Vendor\Mail\Mailer as VendorMailer;
$a = new Mailer(); // App\Service\Mailer
$b = new VendorMailer(); // Vendor\Mail\MailerИмпорт функций и констант
По умолчанию use импортирует классы. Чтобы импортировать функцию или константу, добавьте ключевое слово function или const:
<?php
use function App\Helpers\format_price;
use const App\Config\TAX_RATE;Важный момент: встроенные функции требуют ведущего обратного слеша
Внутри пространства имён неквалифицированное имя функции или класса разрешается сначала против текущего пространства имён. Для встроенных функций PHP автоматически откатывается к глобальной версии, но для встроенных классов — нет. Поэтому обращение к базовым классам, таким как Exception, DateTime или PDO, требует ведущего обратного слеша (или оператора use):
<?php
namespace App\Service;
// Wrong: PHP looks for App\Service\Exception, which doesn't exist.
// throw new Exception('boom');
// Right: leading backslash points to the global class.
throw new \Exception('boom');Распространённый и читабельный подход — импортировать базовый класс в начале файла:
<?php
namespace App\Service;
use Exception;
throw new Exception('boom'); // now the short name worksПолный пример
Этот единый, готовый к запуску скрипт определяет два пространства имён и использует оба — демонстрируя, как одно и то же короткое имя класса может существовать в двух местах без конфликтов:
<?php
namespace App\Billing {
class Invoice
{
public function label(): string
{
return 'Billing invoice';
}
}
}
namespace App\Shipping {
class Invoice
{
public function label(): string
{
return 'Shipping invoice';
}
}
}
namespace Main {
use App\Billing\Invoice;
use App\Shipping\Invoice as ShippingInvoice;
$billing = new Invoice();
$shipping = new ShippingInvoice();
echo $billing->label() . "\n";
echo $shipping->label() . "\n";
}Вывод:
Billing invoice
Shipping invoiceСинтаксис с фигурными скобками
namespace Foo { ... }используется только для размещения нескольких пространств имён в одном файле (удобно для самодостаточного примера). В реальных проектах используется одно пространство имён на файл и автозагрузка Composer.
Пространства имён и автозагрузка (PSR-4)
На практике вы редко вручную прописываете границы пространств имён для каждого файла — этим занимается Composer. Маппинг PSR-4 в composer.json связывает префикс пространства имён с папкой:
{
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
}После этого класс App\Service\Mailer автоматически загружается из src/Service/Mailer.php при первом обращении к нему — без ручных include или require.
Итоги
- Пространство имён группирует классы, интерфейсы, функции и константы для предотвращения конфликтов имён и организации кода.
- Объявляйте его с помощью
namespace App\Service;первым оператором в файле. - Обращайтесь к элементам по полному имени (
\App\Service\Mailer) или, что более распространено, импортируйте их с помощьюuseи используйте короткое имя. - Создавайте псевдонимы для конфликтующих имён с помощью
as, и не забывайте добавлять обратный слеш перед глобальными классами, такими как\Exception, внутри пространства имён. - Автозагрузка PSR-4 сопоставляет префикс пространства имён с каталогом — именно так загружается каждый пакет Composer.