Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

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

Если мы попытаемся определить две разные функции, но с одинаковыми именами, то PHP выдаст ошибку во время запуска кода:

<?php

// file: index.php

function foo()
{
    print_r('one');
}

function foo()
{
    print_r('two');
}
php index.php
# Невозможно переопределить существующую функцию
# Ошибка падает на втором определении
PHP Fatal error:  Cannot redeclare foo() (previously declared in /private/var/tmp/index.php:3)

А если разнести определения этих функций по разным файлам и включить один в другой? Чуда не произойдет - как только интерпретатор встретит новое определение с таким же именем, как и старое, он завершит работу с ошибкой Cannot redeclare (невозможно переопределить существующую функцию).

Давайте порассуждаем над тем, почему это - проблема. Реальные приложения на PHP состоят из многих тысяч строк кода. Значительная часть этого кода приходит из библиотек, написанных другими людьми, и почти наверняка мы не знаем, как они там внутри устроены. Чем больше библиотек вы используете, чем больше разработчиков в проекте и, собственно, кода проекта, тем выше вероятность того, что возникнут дублирующиеся названия. Более того, может оказаться так, что две разные библиотеки, которые вам так нужны в проекте, имеют одинаковые имена функций, а, следовательно, вы физически не сможете их использовать вместе. А включение каждой новой библиотеки в код проекта почти наверняка заставит переименовывать функции самого проекта из-за конфликта имен. Когда-то эта проблема была настолько серьезной, что функции в PHP именовались с префиксами, например, mylibnameSendEmail() или mylibnameAddNewUser(). Таким образом пытались избежать коллизий (пересечений по именам).

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

Files Tree

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

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

Пора переходить к примерам:

<?php

// math.php

namespace math;

function sum($a, $b)
{
    return $a + $b;
}

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

<?php

// index.php

require_once 'math.php';

// Обратиться напрямую к функции sum не получится:
// PHP Fatal error:  Uncaught Error: Call to undefined function sum()
sum(3, 2);

// А если указать пространство имен, то все работает:
\math\sum(5, 8); // 13

Попытка обратиться к функции по имени приведет к ошибке, так как она скрыта за пространством имен. Правильный вызов выглядит так: \<имя пространства имен>\<имя функции>. Рассмотрим еще один пример, когда функция с одним и тем же именем определена в разных пространствах имен.

<?php

// index.php

require_once 'text.php';
require_once 'number.php';

// Эта функция повторяет строчку, переданную первым параметром столько раз, сколько указано во втором параметре:
\text\multiply('hi', 3); // hihihi
\number\multiply(3, 2); // 6

Два пространства имен имеют одинаковые функции, но, как видно из кода, это не создает неудобств. Каждая функция вызывается с указанием собственного пространства имен. Более того, мы можем определить функцию multiply() прямо в том месте, куда производится включение других пространств имен:

<?php

// main.php

require_once 'text.php';
require_once 'number.php';

namespace main;

function multiply($a, $b)
{
    print_r('it works!');
}

function all()
{
    \text\multiply('ho', 2); // hoho
    \number\multiply(3, 2); // 6

    // Такой вызов неявно подставляет текущее пространство \main\
    multiply(2, 3); // it works!
}

Обратите внимание на последний вызов. Функции находящиеся внутри одного пространства имен могут вызывать друг друга напрямую.


Дополнительные материалы

  1. Официальная документация

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

Открыть доступ

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

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы
Иконка программы PHP-разработчик
Профессия
с нуля
Разработка веб-приложений на Laravel
30 марта 10 месяцев

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»