Пространства имен в PHP, разъяснение

в 7:56, , рубрики: Без рубрики

Прим.пер.: Я в курсе, что на момент перевода актуальная версия PHP — 5.5, а также что есть мудрая книга мануал. Но мне показалось интересным, то как автор преподносит namespace функционал, возможно кому-то из тех, кто только постигает азы (да и не только, есть немало бородатых разработчиков, остановившихся на PHP 5.2), статья поможет проникнуться. Ходор.

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

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

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

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

Глобальное пространство имен

Вот такой, очень простой класс:

<?php

// app/models/Eddard.php

class Eddard
{

}

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

<?php

// app/routes.php

$eddard = new Eddard();

Дейл, я как бы, знаю PHP...

Хорошо, хорошо, извини. Суть в том, что мы можем думать об этом классе, как находящимся в глобальном пространстве имён.Я не совсем уверен, что это правильный термин, но на мой взгляд это звучит вполне уместно. Собственно, это значит то, что класс не принадлежит никакому пакету, просто обычный класс.

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

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

<?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 StarkEddard();

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

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

ThisNamespaceAndClassCombinationIsSillyButWorks

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

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

<?php

namespace Stark;

// app/routes.php

$eddard = new Eddard();

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

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

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

<?php

// app/routes.php

$eddard = new Eddard();

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

А сейчас включи свое воображение. Представь, что у нас есть класс из пространства имен TullyEdmure. Сейчас нам нужно использовать его внутри пространства Stark. И как нам это сделать?
Пространства имен в PHP, разъяснение

<?php

namespace Stark;

// app/routes.php

$edmure = new TullyEdmure();

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

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

<?php

namespace Stark;

use TullyEdmure;

// app/routes.php

$edmure = new Edmure();

Используя директиву use, мы можем получить класс из другого пространства имён. Только пожалуйста, не спрашивайте меня, «а почему мы не поставили здесь косую черту в начале?», потому что я просто не знаю. Насколько я знаю — это единственное исключение. Нет, вы можете использовать косую черту здесь. но смысла в этом не будет никакого.

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

<?php

namespace Stark;

use TullyBrynden as Blackfish;

// app/routes.php

$brynden = new Blackfish();

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

<?php

namespace Targaryen;

use DothrakiDaenerys as Khaleesi;

// app/routes.php

class Daenerys
{

}

// TargaryenDaenerys
$daenerys = new Daenerys();

// DothrakiDaenerys
$khaleesi = new Khaleesi();

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

<?php

namespace Targaryen;

use DothrakiDaenerys;
use StarkEddard;
use LannisterTyrion;
use SnowJon as Bastard;

Структура

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

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

DayleBlogContentPost
DayleBlogContentPage
DayleBlogTag

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

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

Недостатки

По правде говоря, я чувствую себя немного виноватым за то, что назвал этот подзаголовок «Недостатки». То, о чем я собираюсь говорить, на самом деле ошибкой не является.

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

In Java for example, you are able to import a number of classes into the current namespace by using the import statement with a wildcard. In Java, ‘import’ is equivelent to ‘use’, and it uses dots to separate the nested namespaces (or packages). Here’s an example.

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

import dayle.blog.*;

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

В PHP у вас так не выйдет. Вы должны импортировать каждый класс в отдельности. Извините. Собственно, почему я извиняюсь? Иди и жалуйтесь команде разработчиков PHP, но я прошу вас — будьте вежливы. Они сделали много интересного в последнее время.

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

<?php

namespace Baratheon;

use DayleBlog as Cms;

// app/routes.php

$post = new CmsContentPost;
$page = new CmsContentPage;
$tag  = new CmsTag;

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


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

Автор: PopeyetheSailor

Источник

Поделиться

* - обязательные к заполнению поля