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

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

В 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

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, например, вы можете импортировать несколько классов в текущее пространство имен, используя оператор импорта. В Java, import является аналогом use и он использует точки, чтобы отделить вложенные пространства имен (или пакеты). Вот пример:
import dayle.blog.*;

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

В PHP у вас так не выйдет. Вы должны импортировать каждый класс в отдельности. Извините. Собственно, почему я извиняюсь? Идите и жалуйтесь команде разработчиков 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;

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



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

Similar posts

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 62

    +1
    В PHP нельзя импортировать сразу несколько классов из-за особенности работы языка. Если Java может легко узнать какие классы находятся в пакете (namespace), то PHP так не может, там все динамически и заранее какие классы находятся в namespace'e узнать невозможно. Да и namespace в PHP это как макросы, все названия классов раскрываются на этапе трансляции в байткод, а не во время выполнения.
      +5
      Это так, но в организации кода, а особенно при интеграции с другими наработками всё же серьёзно помогает. Так уж лучше такие namespace чем никаких.
        0
        В PHP нельзя импортировать сразу несколько классов из-за особенности работы языка

        «из-за особенностей реализации нэймспэйсов» будет вернее. :)
          0
          В PHP ClassLoader может грузить классы откуда угодно и как угодно, заранее узнать список классов в одном namespace невозможно. Как это можно было бы реализовать? Вводить волшебный метод classloader'у, который будет возвращать список классов в пакете? Или как?
        +1
        Если бы не подзаголовок «Недостатки», я бы уже подумал, что автор кроме PHP больше ничего не видел — столько радости от каждой новой возможности. А наверное просто стиль повествования такой.
        Ну а в целом выглядит на подобие многих других языков, что и хорошо, на мой взгляд. Единственное — необычно выглядят бэкслеши.
          +2
          Да, я старался передать авторский стиль повествования. Строго и серьезно можно прочесть на php.net, тут более вольно, и это, кому-то, возможно, поможет создать более полное представление.
            +2
            Бэкслэши возникли оттого, что точка — конкатенация строк — много срача было по этому поводу в php-dev maillist. Ну и еще одна причина — php dev team не осилили написать парсер, который бы отличал вызов статик метода от неймпейса.

            Вообщем, это яркий пример того, как изначальное уродство непродуманного синтаксиса («точка») порождает чудовищных монстров в будущем.
              0
              Как, простите, вызов статик методов связан с бекслешами в php?
                0
                Раньше был вариант использовать двойное двоеточие вместо обратного слэша. Потом от него отказались.
                +1
                А по мне — так слеши выглядят элегантнее. Сразу видно — структура.
                  +1
                  Не осилили? Суть в том, что у нас может быть как статическая функция в классе User, так и функция в пространстве имён User. Если будет одно и то же название — разработчику сложно будет ориентироваться (если, конечно, вообще возможно написать корректный парсер для данной ситуации, не прибегая к использованию приоритетов или фатальных ошибок на совпадение имён).

                  Вы точно знаете PHP и историю его создания?
                  Это «изначальное уродство непродуманного синтаксиса» было продуманно изначально. Да, могли использовать какой-нибудь плюсик для конкатенации строк, но тогда не работал бы подобный финт ушами: 1 + «1». Зачем нужно было автоматическое приведение типов? Автор(ы) хотел добиться поведения, подобного SQL.

                  И, как по мне, различный синтаксис для различных по сути вещей это хорошо, поскольку разработчику не нужно ни на мгновение задумываться, мол, что же это такое, вызов метода экземпляра или вызов функции, находящейся в пространстве имён?
                +1
                >Но мне показалось интересным, то как автор преподносит namespace функционал
                Это из-за отсылок к игре престолов?
                Ну и да, почитайте на досуге, что такое функционал, functionality переводится не так, ровно как и function
                  +1
                  Ознакомился, все сложно, взять хотя бы ru.wiktionary.org/wiki/функционал 2-е значение. Но спасибо, я на ус намотаю.
                    0
                    Это жаргонизм. Меня, например, он слегка раздражает. Как минимум, потому что его обычно используют менеджеры, которые жутко любят аббревиатуры и сокращения. Раздражает примерно так же, как «прога», «комп», «прогер» и т.п. Сам всегда говорю «функциональность», но других не исправляю.
                    +3
                    Идея с Игрой Престолов выглядит красиво и интересно, но имена классов стали не читабельны =(

                    Мне непонятен один момент, Вы пишите:
                    Представь, что у нас есть класс из пространства имен Tully\Edmure

                    Я думал, что «Tully\Edmure» это и есть иерархия неймспейсов (про которую вы чуть выше написали), но далее оказывается, что пространство имён называется «Tully», а имя класса в этом пространстве «Edmure».
                    Так оно и есть, или я что-то неправильно понял?
                      +1
                      Я поправил, не очень правильно перевел — да, namespace — Tully, класс — Edmure.
                      А как понять, что имена не читабельны? Я не решился в коде использовать русскоязычные имена:
                      <?php
                      
                      namespace Старк;
                      
                      $endmar = new \Талли\Эдмар;
                      

                      А то ведь кто-то подумает «Почему бы и нет».
                        +1
                        Собственно говоря — почему бы и нет :) Интерпретатору абсолютно все равно, кириллица или латиница. Другой вопрос — а зачем? Столкнулся я раз с версткой, где CSS-классы были на русском — уж не знаю, прикол-ли верстальщика это был, или его «уникальный почерк» — но валерьянку пришлось пить литрами.
                          +1
                          Я не отрицал, что интерпретатору ровно. Вот зачем — правильный вопрос.
                          –3
                          Ну, и почему бы и нет?
                            +6
                            Потому что после Васи в код полезет Джон, и сильно удивится переменным $водка, $балалайка, $матрешка.
                              –2
                              Т.е. комментариям на русском, а самое главное, документации на продукт на русском он не удивится, а переменные — ужас-ужас? Или предполагается, что Джон по наитию должен в продукте разбираться?
                                +2
                                как то друг уехал в вильнюс на пол года в коммандировку писать софт для банка. Там весь код был на литовском транслите. ТОесть неподготовленый человек читает его как результат работы декомпилятора. Зачем так издеваться? Мало ли кто с вашим кодом работать будет. Без документации я то обойдусь если код адекватный, но зачем усложнять чтение самого кода. Да и если опенсорс то не факто что ктото не стянет вашу либу с гитхаба.

                                К тому же зачем превращать в лапшу код если стандартная библиотека на англыйском и куча библиотек на нем же. Мне даже раскалдку лень будет менять
                                  –3
                                  Если литовцам так удобно, что с того? При чём здесь издевательство и так далее? Документацию к коду и комментарии в коде ваш друг тоже не смог прочитать или там всё на английском?
                                    +1
                                    Писать надо так. чтоб было удобно не кому-то одному, а всем. Для этого стандарты кодирования и придумывают. И если в один прекрасный момен вы станете Гуглом, а у вас во всех проектах вместо $collection->getDataProvider() чтото типа $kolekcija->gautiDuomenuTeikejas(), я вам не завидую
                                      +1
                                      Сломали мне мозг, я пытался это прочитать как транслит с русского.
                                        0
                                        Да-да, у вас интерфейс на русском без возможности локализации в кодировке CP1251, вся документация, все комментарии, всё на русском и вы, хоп, впезапно стали Гуглом, но если у вас имена функций и переменных на русском, то всё в порядке.
                                          0
                                          Писать надо так. чтоб было удобно не кому-то одному, а всем.

                                          В рыночных реалиях «всем» трансформируется во «всем работающим над проектом в обозримой перспективе» в лучшем случае. Остальным «всем» в лучшем случае приходится довольствоваться «вот станем гуглом (тут скорее фэйсбук или вконтакте должны быть) — перепишем, а сейчас времени и денег нет».
                                      –1
                                      Не знаком с особенностями российского Software Development: техническая документация обычно по-русски пишется?
                                        0
                                        Простите, а на каком языке в России её писать-то?
                                          0
                                          Я просто был под впечатлением, что достаточно большая часть «пост-советского» IT работает на международных проектах (в той или иной степени). Возможно, это не касается вашей отрасли (или вообще мое впечатление ошибочно). Получается, что внутренний рынок вполне себе развит.
                                            +1
                                            Большая часть постсоветского айти клепает сайтики по 1000 р штучка, где никакой Джон даже час не будет смотреть на этот код.
                                              0
                                              Это довольно печально… Тогда с появлением все более и более «дружелюбных» CMS рынок будет мельчать и выродится в поделки студентов, умещих читать мануалы к ним. Ну и дезайнеры всегда свой хлеб найдут — картинки рисовать.
                                              Тогда-то программисты к Джону и пойдут (судя по моему плодотворному сотруднечеству с украинцами)
                                                0
                                                Тогда и будут писать по-английски :)
                                              0
                                              Получается, что внутренний рынок вполне себе развит.

                                              На удивление да. Причём в большей части это касается именно российского рынка, а не вообще пост-советского. Думаю факторов, объясняющих это много: тут и «халявные» нефтедоллары, и сотня миллионов потенциальных пользователей, и исторически сложившаяся моноязычность в том числе среди разработчиков, дизайнеров и т. п.
                                          0
                                          Как ни странно, я заметил закономерность — если человек пишет в PHP коде комментарии по-русски, то эти комментарии такие же нечитаемые, как и его код.
                                            0
                                            Какие-то дикие суеверия, хоссподи.
                                          –3
                                          Это просто традиция, священная корова — писать названия функций и переменных на английском в проекте, где:

                                          a) нет ни одного разработчика, который не знал бы русский, зато обилите тех, кто не знает английский
                                          б) у которого вся документация, все описания алгоритмов, все блок-схемы и выписанные сущности на русском
                                          в) у которого только русский интерфейс и даже без возможности локализации
                                          г) у которого ещё и кодировка CP1251
                                          д) у которого исключительно внутренний рынок

                                          но названия функций и переменных на английском. А то, вдруг, Джон прийдёт, ему же неудобно будет!
                                            +2
                                            А вы пишете на PHP? Если да, то используете ли вы русский язык в своем коде, если доподлинно знаете, что Джон в него нос не сунет?
                                              –1
                                              Если для себя — иногда пишу. Если не для себя — нет. Все вокруг слишком уверены, что Джон нос сунет.
                                                +2
                                                Ок, спасибо, я понял вашу позицию.

                                                Для себя я решил, что стоит придерживаться некоего принятого стиля написания кода, близкого к стандартам, чтобы облегчить себе, в первую очередь, участь, а также не шокировать окружающих.
                                                  –2
                                                  Писать имена функций и переменных на смешном корявом английском — это стандарт?
                                                    0
                                                    image
                                                      0
                                                      Вы подумали я троллю? Защитный рефлекс, срабатывающий, когда трогают Священную Корову Английских Имён?
                                                      0
                                                      В целом, плохо, если человек-программист ещё и человек-корявый-английский. Большинство адекватной и свежей документации пишется на английском, большинство решений проблем описано на английском. Я вообще мало доверяю программистам, не знающим английский (при этом разговорный не обязателен).

                                                      При программировании на PHP мне, по сути, достаточно двух ресурсов:
                                                      1. php.net, на котором все обсуждения специфики работы функций/пакетов/классов на английском
                                                      2. stackoverflow.com вообще всё на английском

                                                      И мне не совсем (совсем не) понятно, с каким ресурсами работают программисты, не знающие языка.
                                                        +1
                                                        Вы знаете, умения нормально читать на английском и плохо на нём писать нормально сочетаются.

                                                        Кстати, я, вот, начинал программировать не зная английского языка и даже без интернета, ничего, выжил как-то. Своей головой до всего доходил.
                                                0
                                                Одна из причин, кроме Джона — английский как правило короче, а разработчики люди ленивые :) Плюс для некоторых общепринятых сущностей типа паттернов не существует адекватных однозначных переводов на русский.
                                                  0
                                                  Я заметил, что те, кто пишут комментарии/документацию на русском, кодят и документируют примерно так:
                                                      /**
                                                       * Функция получает информацию о валютном аккаунте этого кошелька.
                                                       * Данные затем сохраняются в поле $accountData.
                                                       * Операция также считается успешной, если данные найдены в поле
                                                       * Пустой $currencyName означает запрос на все аккаунты кошелька
                                                       * $accountData, хоть запроса при этом и не выполняется.
                                                       * @param string $currencyName
                                                       * @return boolean $success
                                                       */
                                                      public function getAccountData($currencyName = "")
                                                  
                                                      /**
                                                       * Функция готовит данные для отображения кошелька. Возвращается айди и вся
                                                       * информация по аккаунтам. Можно передать массив с нужными типами
                                                       * аккаунтов. Если этого не сделано, запрашиваются данные по всем.
                                                       */
                                                      public function getDisplayData(...)
                                                  


                                                  Если у таких людей отобрать русский язык, они автоматически постепенно учатся кодить так, чтобы их код говорил за себя. Хоть и не всегда.
                                        +4
                                        Глобальное пространство имен

                                        Если уж приводить примеры по пространствам имён, правильнее было бы приводить пример (моё имхо):

                                        <?php
                                        
                                        // app/routes.php
                                        
                                        namespace
                                        {
                                            class Eddard
                                            {
                                            }
                                        }
                                        

                                        Может это всем очевидно, но мне по чистой случайности удалось узнать именно о таком указании глобального пространства. Буду рад, если кому не придётся набивать шишки, попытками написать "namespace \;", "namespace global;" и проч.
                                          0
                                          А что, документацию уже не модно читать что ли?

                                          ru2.php.net/manual/en/language.namespaces.definitionmultiple.php#example-239
                                            0
                                            Там полтора десятка страниц по пространствам. Не заметил значит, спасибо за ссылку.
                                            0
                                            А для чего такое может пригодиться?
                                              0
                                              Например когда вставляешь код из разных файлов в один для постинга в пастбине =) В общем специфические задачи, когда требуется уйти от стандарта — один класс в одном файле.
                                            +2
                                            Дейнерис по отцу Таргариен.
                                              +3
                                              Хотел бы уточнить, что мы можем брать часть пространства имён и без присвоения псевдонима:
                                              use Dayle\Blog;
                                              $post = new Blog\Content\Post;
                                              $page = new Blog\Content\Page;
                                              $tag  = new Blog\Tag;
                                              

                                              И если нет конфликтов, то я предпочитаю именно этот вариант, просто потому что он проще.
                                                0
                                                Не, я может быть не в тему, но к чему тут тег winter is coming?
                                                  0
                                                  Девиз дома Старков, его глава, которого в сериале играет Шон Бин, представлен на КДПВ. По такому тегу, предположительно, можно найти статьи, связанные с «Песней льда и пламени» на хабре. Just for lulz, в общем.
                                                    0
                                                    В каком сериале? :) Немного раздражает когда авторы и/или переводчики предполагают знание не только английского языка, но и какого-то культурного контекста.
                                                      0
                                                      Сериал — «Игра престолов» («Game of thrones»), изначально по циклу «Песнь льда и пламени» (рекомендую).
                                                        0
                                                        Я ни одной серии этого сериала не посмотрел, но уже после пары неймспейсов понял, «об чём речь». Хотя сначала я было обрадовался, что кто-то использует имена мифических исландских (например) персонажей. Ан нет, всё то же, что и вчера, и позавчера.
                                                      +1
                                                      Такой тонкий юмор автора (переводчика?) наверное: у покемонов по прозвищу «Слоупок» зима тоже только начинается. Ну и пространства имен в PHP тоже, того этого… не первый год.
                                                        0
                                                        Пойти написать пост про то, как правильно кодировать и проверять пароли с помощью библиотеки crypt, что ли.
                                                      +1
                                                      Вот это предложение слегка нечитабельно: «Представь, что у нас есть класс из другого пространства имен под, названный Tully\Edmure.»

                                                      А вообще, спасибо за статью.

                                                      Only users with full accounts can post comments. Log in, please.