PHP NameSpace — как же все-таки его готовить? Пространства имен в PHP, разъяснение Php namespace использование.

Недавно инкапсулировал свой проект в namespace и столкнулся с проблемой отсутствия нормальной документации. Все, что удалось найти датируется примерно 2009 годом, а на дворе почти 2012… В найденном материале куча нерабочих мест, использующих то, что в нынешней версии php нет. В связи с этим хочу немного осветить этот вопрос.
Итак, что же такое Namespace или пространство имен? Великая wikipedia определяет их так:

Пространство имён (англ. namespace) - некоторое множество, под которым подразумевается модель, абстрактное хранилище или окружение, созданное для логической группировки уникальных идентификаторов (то есть имён). Идентификатор, определенный в пространстве имён, ассоциируется с этим пространством. Один и тот же идентификатор может быть независимо определён в нескольких пространствах. Таким образом, значение, связанное с идентификатором, определённым в одном пространстве имён, может иметь (или не иметь) такое же (а скорее, другое) значение, как и такой же идентификатор, определённый в другом пространстве. Языки с поддержкой пространств имён определяют правила, указывающие, к какому пространству имён принадлежит идентификатор (то есть его определение).wiki

Все ясно? На самом деле все просто. До версии 5.3 в php существовало всего два пространства - глобальное(в котором выполнялся ваш основной код) и локальное(в котором определялись переменные функций).

С версии 5.3 все изменилось. Теперь можно определить свое пространство имен, в котором будут существовать ваши классы методы и т.д.


Надеюсь стало немного понятнее.

Я специально обозвал классы одинаково. Так они определены в разных пространствах, то это два разных класса, несмотря на одинаковые имена. Основной скрипт,-по прежнему, функционирует в глобальном пространстве, здесь ничего не изменилось и в нем, по-прежнему, можно определять классы и функции. Так для чего же тогда нужны пространства? Прежде всего, для уверенности в том, что когда вы подключаете файл, с каким-нибудь фреймворком или библиотекой, ваши классы не переопределят классы фреймворка или наоборот.

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

Внимание: по каким-то своим основаниям php не допускает использование ключевого слова use в блоках условий и циклах

Возьмем пример с картинок и воплотим его в коде:

Внимание: ключевое слово namespase должно быть расположено в самом начале файла сразу после
файл A.php
файл B.php
Возможен альтернативный синтаксис:
Рекомендуется объявлять каждое пространство имен в отдельном файле. Хотя можно и в одном, но это строго не рекомендуется!
Теперь переместимся в третий файл, в котором будет функционировать наш основной скрипт
index.php
казалось бы в чем преимущество, только кода прибавилось, однако это не совсем так, чуть дальше я приведу пример класса автозагрузки, с которым строки подключающие файлы с классами будут ненужны.
А теперь обратимся к нашим классам

Внимание: использование оператора разрешения области видимости (::) в пространствах имен php не допускается ! Единственное для чего он годится - это для обращения к статичным методам класса и константам. Вначале хотели использовать для пространства имен именно его, но затем из-за возникших проблем отказались. Поэтому конструкция вида A::A::say(); недопустима и приведет к ошибке.

Для пространств имен необходимо использовать символ обратного слеша "\"
Внимание: во избежание недоразумений необходимо экранировать данный символ при его использовании в строках: "\\"

Пространства имен можно вкладывать друг в друга, дополним наш файл A.php:
а в индексе напишем следующее:

Важным моментом является использование алиасов для импортированных пространств. Можно было написать A\subA::say(); согласитесь, каждый раз писать полные пути к пространствам затруднительно для того, чтобы этого избежать были введены алиасы. При компилировании произойдет следующее вместо алиаса sub будет подставлено A\subA, таким образом мы получим вызов A\subA::say();

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

Для того чтобы не было проблем с автозагрузкой классов из пространств файловую систему нужно организовать аналогично организации пространств. Например, есть у нас корневая папка classes, где и будут храниться наши классы, тогда наши пространства могут быть организованы следующим образом
classes\A\A.php
classes\A\sub\A.php(подпространство sub вынесем в отдельный файл)
classes\B\B.php

В php есть магическая константа __NAMESPACE__ которая содержит имя текущего пространства.

А теперь об автозагрузке.

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

" .$file ." in " .$filepath)); if (file_exists($filepath)) { if(Autoloader::debug) Autoloader::StPutFile(("подключили " .$filepath)); $flag = FALSE; require_once($filepath); break; } Autoloader::recursive_autoload($file, $path2, &$flag); } } closedir($handle); } } private static function StPutFile($data) { $dir = $_SERVER["DOCUMENT_ROOT"] ."/Log/Log.html"; $file = fopen($dir, "a"); flock($file, LOCK_EX); fwrite($file, ("║" .$data ."=>" .date("d.m.Y H:i:s") ."

" .PHP_EOL)); flock($file, LOCK_UN); fclose ($file); } } \spl_autoload_register("yourNameSpace\Autoloader::autoload"); }
Если посмотреть на имена классов, которые приходят для загрузки, то будет видно, что каждый класс предваряется префиксом из пространства имен, которое указано в use. Именно поэтому рекомендую использовать расположение файлов в каталогах аналогично пространству имен, это ускоряет поиск до одной-двух итераций.

Теперь наш индекс можно написать так:
теперь все классы и интерфейсы, которые вы будет использовать будут загружены автоматически.

Для демонстрации некоторых динамических возможностей языка с пространствами объявим еще один класс:
test.php

Index.php
sayName("test"); //а можно так test\sayName("test2"); //или так $obj::sayName("test"); //а можно так test::sayName("test2");

Надеюсь, что моя статья будет полезна кому-нибудь.

Сегодня мы с Вами в стиле как для полных дэбилов, в хорошем смысле сиго слова, постараемся разобраться в том, что такое пространства имён в PHP 5.

Что такое пространство имён в PHP 5

Значит, как для полных дэбилов, опять же только в хорошем смысле этого слова, скажем, что пространства имён в PHP 5 (да и в С и С++) - это как имена городов России или Украины, которые содержат в себе имена улиц. Например в одном и том же городе, как и в пространстве имён, Москва к примеру, не может существовать несколько названий улиц с именем "Путлеровская 666" - согласны? Ок.

Кроме определяемых пространств имён существует ещё и глобальное пространство имён PHP, в котором тусуются все базовые функции и классы, а также те, которые были определены в подключаемых файлах и которым не было назначено определённое пространство имён. По анологии с реальной жизнью можно сказать, что бомжи, гопники, проститутки и другие приблуды по сути являются теми же функциями и классами, которым не было назначено определённое место жительства (пространство имён ) и которые живут просто в глобальном пространстве России, - ака "мой адрес не дом и не улица, мой адрес советский союз".

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

Ранее, до версии PHP 5.3, как собственно и сейчас, все, находящиеся в подключаемых файлах, константы, функции и классы автоматически размещались в глобальном пространстве PHP.

Таким образом, если файл Liba1.php с константами, функциями и классами:

require_once ("Liba1.php" ) ; const MYCONST = "MYCONST CONTENT" ; function myFunction() { return __FUNCTION__ ; } class MyClass { static function whoAmI() { return __METHOD__ ; } }

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

\n " ; echo myFunction() . "\n " ; echo MyClass:: whoAmI () . "\n " ; // or $obj = new MyClass() ; echo $obj -> whoAmI () ;

Обратим внимание на то, что согласно последнего стандарта PSR-4 (http://www.php-fig.org/psr/psr-4/) классы следует именовать с большой буквы, как и содержащие их файлы, а методы (функции определённые в классе ) с маленькой буквы - если наш класс назван MyClass , то и имя файла его содержащего должно быть MyClass.php . Соблюдение этого стандарта требуется для успешной автозагрузки классов (ака Autoloader ).

Теперь, когда мы малость раздуплили, что то оно такое пространство имён в PHP 5, то самое время немного поднапрячь моск более умным изложением выше изложенного по приведённым ниже ссылям:

Оператор namespace в PHP 5

Оператор namespace определяет/объявляет текущее пространство имён для класса или текущего исполняемого файла.

Вспомним аналогию пространств имён с городами. Пространства имён можно также сравнить с телефонным справочником (кодами городов), - например мы можем сказать " namespace 38\045 ", что это 38\045 (код страны\код города) пространство телефонов города Киева.

К примеру у нас имеется библиотека/файл с именем MyClass.php

Сам класс MyClass , его методы (функции) и свойства (переменные, константы), будут доступны только из пространства имён App .

Чтобы напрямую использовать MyClass из пространства имён App в нашем исполняемом файле/скрипте, мы должны либо объявить в нём то же " namespace App; " либо использовать " use App\MyClass; ":

whoAmI () ;

В этом примере мы подгружаем наш MyClass.php из той же директории где расположен и исполняемый файл, т.е. без соблюдения стандарта PSR-4. По идее " namespace App; " должно объявляться в файле класса, а не в исполняемом файле, и App при этом (для успешной автозагрузки) должно быть директорией, а имя класса " class MyClass {...} " соответственно именем файла MyClass.php , который должен быть доступен по адресу App/MyClass.php .

Если мы ручками подгрузим MyClass.php и не объявим " namespace App; " или " use App\MyClass; ", то получим " Fatal error: Class "MyClass" not found " ибо в файле класса MyClass.php объявлено пространство имён " namespace App; " (App) и только из него будет доступен класс MyClass , - разумеется если класс с таким же именем (MyClass) не объявлен в глобальном пространстве.

Для использования классов из пространств имён мы должны PHP попросить об этом директивами " use App\MyClass; " или " namespace App; ".

Для успешной автозагрузки мы должны соблюдать стандарт PSR-4 и располагать файлы классов в директориях имена которых соответствуют объявленному пространству имён. Например:

Пространство имён класса MyClass: " namespace App; " Физическое расположение файла: App/MyClass.php Пространство имён класса MyClass: " namespace App\Liba1; " Физическое расположение файла: App/Liba1/MyClass.php Пространство имён класса MyClass: " namespace App\Vasya\Liba1; " Физическое расположение файла: App/Vasya/Liba1/MyClass.php

Про "автозагрузку" классов в PHP 5 поговорим чуть папизже...

Оператор use в PHP 5

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

Ни константы, ни функции не могут быть заимпортированы с помощью оператора use . Действию оператора use подвержены только имена классов и пространства имен. Хотя, кажись, начиная с версии PHP 5.6+ возможно импортирование функций и констант.

  • Импорт и создание псевдонима для класса: use App\Liba1\MyClass as MyAlias;
  • Импорт класса: use App\Liba1\MyClass;
  • Импорт самого пространства имён: use App\Liba1;
  • Импорт глобального класса: use ArrayObject;

Кто-то может спросить " А накой чёрт нам нужен "Импорт глобального класса"? ", - а нужен он для доступа к нему из какого-то пространства имён, например:

Потому как мы находимся в пространстве имён "Vasya", а РНР всегда работает из под текущего пространства имён, то выполнение приведённого выше кода завершится ошибкой " Fatal error: Class "Vasya\ArrayObject" not found in ". Чтобы получить доступ к классу ArrayObject находясь в пространстве имён Vasya нам нужно использовать (раскомментировать) " use ArrayObject; " или претворить имя класса обратным слешем \ArrayObject .

  • Kласс ArrayObject позволяет работать с объектами как с массивами.
  • PHP: Использование пространств имен: импорт/создание псевдонима имени - Manual
  • PHP: Использование пространств имен: переход к глобальной функции/константе - Manual
  • Часто задаваемые вопросы (FAQ): вещи, которые вам необходимо знать о пространствах имен

Автозагрузка классов в PHP 5

Нужно помнить, что PHP всегда работает в текущем пространстве имён. Это значит, что если мы объявили пространство имён " namespace Vasya; " и попытались создать объект класса " $obj = new MyClass(); ", то при использовании функции автозагрузчика "__autoload() " или "spl_autoload_register() " будет выполнена попытка подключить файл по адресу Vasya/MyClass.php . Например:

// Используем пространство имён Васи ) ; return true ; } return false ; } ) ; $obj = new MyClass() ; echo $obj -> whoAmI () ;

Для автоматической загрузки классов функция spl_autoload_register() считается более предпочтительной нежели __autoload() . Функция __autoload() не рекомендуется к использованию и в будущем её поддержка может быть прекращена или она и вовсе может быть удалена. С версии PHP 5.3.0 стало возможным использование безымянных функций (ака "function (){}" ).

Итоги

Появление в PHP пространств имён однозначно является положительным шагом. Если я где-то протупил, тогда, пожалуйста, поправьте меня своими комментариями.

P.S. Статья написана по просьбам трудящихся, которые не смогли осилить официальную документацию.

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

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

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

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

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

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

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

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

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

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

Итак, нам нужно создать нового Эдда, если вы решили что это нужно сделать вот так:
То нет, это не так. Здесь мы получаем экземпляр класса из первого примера, который мы создали ранее. Не тот, в пространстве имен Stark. Давайте попробуем создать экземпляр Эддарда Старка.
Для создания экземпляра класса нам нужно предварить имя класса префиксом из названия пространства имен, которому класс принадлежит, а в качестве разделителя использовать обратную косую черту . В итоге у нас есть экземпляр именно того класса, что нам нужен. Разве это не волшебно?

К слову сказать, пространства имён могут образовывать сколь угодно сложную иерархию, используя столько уровней, сколько потребуется. Например:
This\Namespace\And\Class\Combination\Is\Silly\But\Works

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

Помните, как я сказал вам, что PHP всегда работает относительно текущего пространства имен. Давайте взглянем на это в действии:
Добавив директиву пространства имён, мы дали понять PHP, что мы находимся в пространстве имён Stark. Так как именно в нем мы определили класс Eddard, то именно его мы и получим. Видите - все относительно.

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

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

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

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

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

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

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

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

Структура

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

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

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

Недостатки

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

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

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

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

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

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

Здравствуйте. В сегодняшней статье мы рассмотрим, что такое пространства имён в PHP .

Если вы давно используете ООП , то, наверное, встречали ситуацию, когда, подключая стороннюю библиотеку, у вас случался сбой из-за того, что вы уже используете в своём коде такие же имена классов, как и в библиотеке. Особенно это может случиться, если вы используете такие распрастранённые имена, как "model" , "db" и т.п. О том, как это исправить, я сейчас и расскажу.

Пространство имён(namespace) - это некоторое хранилище, созданное для абстрактной группировки уникальных идентификаторов(имён).

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

Создадим файл myclass.php с таким содержанием

namespace my\oneProject;
class MyClass { }
?>

Здесь мы создали класс в пространстве имён my\oneProject . Кстати, нужно писать именно обратный слеш. Не перепутайте!

Теперь в файле index.php напишем следующее

require_once("myclass.php");
$mc = new MyClass(); // Ошибка: класс не найден
$mc = new my\oneProject\MyClass(); // всё работает
?>

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

Мы можем указывать сразу несколько пространств имён в одном файле

namespace Project;

Const CONNECT_OK = 1;
class Connection { }
function connect() { }

Namespace AnotherProject;

Const CONNECT_OK = 1;
class Connection { }
function connect() { }
?>

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

Мы можем также применять синтаксис со скобками.

namespace Project {

Const CONNECT_OK = 1;
class Connection { }
function connect() { }
}

Namespace AnotherProject {

Const CONNECT_OK = 1;
class Connection { }
function connect() { }
}
?>

Если вы объединяете код в глобальном пространстве имён с кодом в других пространствах, то используется только синтаксис со скобками.

namespace Project {

Const CONNECT_OK = 1;
class Connection { }
function connect() { }
}

Namespace { // глобальный код
session_start();
$a = Project\connect();
echo Project\Connection::start();
}
?>

Также, не забывайте, что определение пространства имён всегда должно идти первой строчкой кода. Если вы напишите так, то будет ошибка

Чтобы узнать, в каком пространстве имён вы сейчас находитесь, можно воспользоваться константой __NAMESPACE__

namespace Project;
echo """, __NAMESPACE__, """; // выведет "Project"
?>

С помощью данной константы можно, например, динамически конструировать имена

namespace Project;

Function incl($classname) {
$a = __NAMESPACE__ . "\\" . $classname;
return new $a;
}
?>

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