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

PHP


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

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

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

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

<?php

// app/models/Eddard.php

class Eddard
{

}

Ничего особенно, как видите, и если вы хотите использовать его, просто сделайте так:

<?php

// app/routes.php

$eddard = new Eddard();

Сразу хотел бы отметить, что сейчас мы еще не говорим о пространствах имен и ни коем образом их не объявляем. А значит, по умолчанию используется глобальное пространство имен. 

Простое использование пространств имён.

Давайте создадим еще одного Эддарда, рядом с тем, глобальным.

<?php

namespace Stark;

// app/models/another.php

class Eddard
{

}

Здесь у нас очень похожий класс с одним небольшим изменением, добавлена директива пространства имен. Строка namespace Stark;говорит PHP что мы работаем в пространстве имен Stark и любой код (объявление классов, функций, переменных и т.д.) будет относиться к нему. 

Итак, нам нужно создать нового Эдда, если вы решили что это нужно сделать вот так:

<?php

// app/routes.php

$eddard = new Eddard();

То нет, это не так. Здесь мы получаем экземпляр класса из первого примера, который мы создали ранее. Не тот, в пространстве имен Stark. Давайте попробуем создать экземпляр Эддарда Старка.

<?php

// app/routes.php

$eddard = new Stark\Eddard();

Для создания экземпляра класса нам нужно предварить имя класса префиксом из названия пространства имен, которому класс принадлежит, а в качестве разделителя использовать обратную косую черту. В итоге у нас есть экземпляр именно того класса, что нам нужен. 

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

This\Namespace\And\Class\Combination\Is\Silly\But\Works

Теория относительности.


Помните, как я сказал вам, что PHP всегда работает относительно текущего пространства имен. Давайте взглянем на это в действии:

<?php

namespace Stark;

// app/routes.php

$eddard = new Eddard();

Добавив директиву пространства имён, мы дали понять PHP, что мы находимся в пространстве имён Stark. Так как именно в нем мы определили класс Eddard, то именно его мы и получим. Видите — все относительно.

Сейчас, когда мы изменили пространство имён, у нас возникла одна маленькая проблема.  А как нам теперь получить наш оригинальный класс Eddard? Ну тот, который в глобальном пространстве?

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

<?php

// app/routes.php

$eddard = new \Eddard();

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

А сейчас представь, что у нас есть класс из другого пространства имен, названный Tully\Edmure. Сейчас нам нужно использовать его внутри пространства Stark. И как нам это сделать?

<?php

namespace Stark;

// app/routes.php

$edmure = new \Tully\Edmure();

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

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

<?php

namespace Stark;

use Tully\Edmure;

// app/routes.php

$edmure = new Edmure();

Используя директиву use, мы можем получить класс из другого пространства имён. 

А, еще один маленький трюк! Мы можем дать нашим импортируемым классам "прозвища":

<?php

namespace Stark;

use Tully\Brynden as Blackfish;

// app/routes.php

$brynden = new Blackfish();

Используя ключевое слово as, мы присвоили классу Tully/Brynden прозвище Blackfish, что позволяет нам использовать новое прозвище для его идентификации в текущем пространстве имен. Ловко, не так ли? Это также очень удобно, если вам нужно использовать два класса, названных одинаково, в пределах одного пространства имён:

<?php

namespace Targaryen;

use Dothraki\Daenerys as Khaleesi;

// app/routes.php

class Daenerys
{

}

// Targaryen\Daenerys
$daenerys = new Daenerys();

// Dothraki\Daenerys
$khaleesi = new Khaleesi();

Давая Daenerys из пространства Dothraki прозвище Khaleesi, мы можем использовать оба класса Daenerys. Довольно удобно, там мы можем использовать все необходимые классы в нашем приложении.

<?php

namespace Targaryen;

use Dothraki\Daenerys;
use Stark\Eddard;
use Lannister\Tyrion;
use Snow\Jon as Bastard;

Структура.

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

Скажем, необходимо создать библиотеку с открытым исходным кодом. Необходимо, чтобы другие могли использовать этот код.

Беда в том, что имена классов в этом коде будут конфликтовать с собственным приложением пользователя  библиотеки. Это недопустимо. Вот как можно решить эту проблему:

Dayle\Blog\Content\Post
Dayle\Blog\Content\Page
Dayle\Blog\Tag

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

Начав использовать composer, вы узнаете, как использовать пространства имён для упрощения автозагрузки кода. Я настоятельно рекомендую вам взглянуть на этот полезный механизм.

Недостатки

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

В Java, например, вы можете импортировать несколько классов в текущее пространство имен, используя оператор импорта. В Javaimport является аналогом use и он использует точки, чтобы отделить вложенные пространства имен (или пакеты). Вот пример:

import dayle.blog.*;

Здесь произойдет импорт всех классов, находящихся в пакете ‘dayle.blog.

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

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

<?php

namespace Baratheon;

use Dayle\Blog as Cms;

// app/routes.php

$post = new Cms\Content\Post;
$page = new Cms\Content\Page;
$tag  = new Cms\Tag;

Это может быть полезным при использовании большого числа классов. 


Вы можете помочь развитию сайта отправив любую сумму

Комментарии

  1. ijadeyasuw
    14.06.2019 в 07:19

    Подскажите, возможна помощь в настройке?

  2. oritisiqume
    14.06.2019 в 08:02

    Доходчиво, спасибо.

Написать комментарий