W3docs

Пространства имён 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.

Практика

Практика
Каковы цели пространств имён PHP?
Каковы цели пространств имён PHP?
Was this page helpful?