Пространства имен в PHP, разъяснение. Пространства имен в PHP, разъяснение Php namespace использование

Сегодня мы с Вами в стиле как для полных дэбилов, в хорошем смысле сиго слова, постараемся разобраться в том, что такое пространства имён в 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. Статья написана по просьбам трудящихся, которые не смогли осилить официальную документацию.

(PHP 5 >= 5.3.0, PHP 7)

Before discussing the use of namespaces, it is important to understand how PHP knows which namespaced element your code is requesting. A simple analogy can be made between PHP namespaces and a filesystem. There are three ways to access a file in a file system:

  1. Relative file name like foo.txt . This resolves to currentdirectory/foo.txt where currentdirectory is the directory currently occupied. So if the current directory is /home/foo , the name resolves to /home/foo/foo.txt .
  2. Relative path name like subdirectory/foo.txt . This resolves to currentdirectory/subdirectory/foo.txt .
  3. Absolute path name like /main/foo.txt . This resolves to /main/foo.txt .
The same principle can be applied to namespaced elements in PHP. For example, a class name can be referred to in three ways:
  1. Unqualified name, or an unprefixed class name like $a = new foo(); or foo::staticmethod(); currentnamespace , this resolves to currentnamespace\foo foo . One caveat: unqualified names for functions and constants will resolve to global functions and constants if the namespaced function or constant is not defined. See Using namespaces: fallback to global function/constant for details.
  2. Qualified name, or a prefixed class name like $a = new subnamespace\foo(); or subnamespace\foo::staticmethod(); . If the current namespace is currentnamespace , this resolves to currentnamespace\subnamespace\foo . If the code is global, non-namespaced code, this resolves to subnamespace\foo .
  3. Fully qualified name, or a prefixed name with global prefix operator like $a = new \currentnamespace\foo(); or \currentnamespace\foo::staticmethod(); . This always resolves to the literal name specified in the code, currentnamespace\foo .

Here is an example of the three kinds of syntax in actual code:

namespace Foo \ Bar \ subnamespace ;

const FOO = 1 ;
function foo () {}
class foo
{
}
?>

namespace Foo \ Bar ;
include "file1.php" ;

const FOO = 2 ;
function foo () {}
class foo
{
static function staticmethod () {}
}

/* Unqualified name */
foo (); foo :: staticmethod (); echo FOO ;

/* Qualified name */
subnamespace \ foo (); // resolves to function Foo\Bar\subnamespace\foo
subnamespace \ foo :: staticmethod (); // resolves to class Foo\Bar\subnamespace\foo,
// method staticmethod
echo subnamespace \ FOO ; // resolves to constant Foo\Bar\subnamespace\FOO

/* Fully qualified name */
\ Foo \ Bar \ foo (); // resolves to function Foo\Bar\foo
\ Foo \ Bar \ foo :: staticmethod (); // resolves to class Foo\Bar\foo, method staticmethod
echo \ Foo \ Bar \ FOO ; // resolves to constant Foo\Bar\FOO
?>

Note that to access any global class, function or constant, a fully qualified name can be used, such as \strlen() or \Exception or \INI_ALL . ?>

PHP, начиная с версии 5.3, подарил нам пространство имен. С тех пор идет где-то вялое, а где-то бурное обсуждение, как же это пространство имен использовать?
Некоторые фреймворки, такие как Symphony, Laravel, и, конечно же Zend взяли эту технологию на вооружение.
Все это более или менее вписалось в схему MVC. Осталась одна, наверное вечная, дискуссия, какой же должна быть главная брачная пара приложения - Модель и Контроллер?
Одни нам говорят, что Модель должна быть дородной и толстой и при ней стройный и тонкий Контроллер. Одним словом - матриархат.
Другие, наоборот, считают, что Контроллер должен всем управлять и повелевать, поэтому он получается основательный, упитанный. И при нем худенькая, стройненькая Модель, задача которой сводится к подай-принеси. Такой вот патриархат.
Так что же лучше в схеме MVC? Патриархат или матриархат?
Давайте посмотрим на это с точки зрения построения семейной ячейки на основе демократии. И пусть Namespace нам в этом поможет.

Нам не нравятся толстые, неуклюжие Контроллеры, которые, как слон в посудной лавке, по неосторожности могут раздавить все приложение.
Нам не нравятся также толстые Модели. Ну а кому они нравятся? Они должны быть достойны подиума!
Давайте попробуем с помощью Namespace, как с хорошей сватьей, создать гармоничную семью.

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

Мы создали основну структуру, где:

  • Blog - это хранилище нашего приложения;
  • Views и Templates - хранилище представлений и шаблонов;
  • Utility - хранилище общих библиотек;
  • index.php - bootstrap скрипт;
  • Post - вот здесь и должна состояться семейная идиллия Контроллера и Модели.

С index.php все просто:

run(); /* * end of index.php */

Определяем нужные пути и создаем автозагрузчик.
Автозагрузчик загружает необходимые классы, которые расположены в иерархии папок согласно пространству имен класса. Например, класс BlogPostServicesView будет разыскиваться в Blog/Post/Services.
А вот и первая встреча с Namespace.
При старте index.php мы создаем экземпляр приложения Blog, класс которого загружается из Blog/Blog.php.
Посмотрим на него.

post = new Post(); } public function run() { $this->post->view->all(); } }//end class Blog

При создании класса Blog мы внедряем в него класс Post с Namespace BlogPost и автозагрузчик загружает его из Blog/Post/Post.php.
Наверное, этот класс и можно назвать Контроллером,

view = new View(); } }//end class Post

Сущность Post включает в себя:
- структуру самой записи данных - BlogPostEntitiesPostEntity.php

Службы, обслуживающие запросы Контроллера - BlogPostServicesView.php (одна из служб, для примера)

db = new DB(); }//end __construct public function all() { $posts = $this->db->survey(); Contemplate::compose(array("header" => "header", "main" => "main", "footer" => "footer",), array("posts" => $posts, "title" => "Viper site",)); } }//end class PostView

Систему взаимодействия с базой данных - BlogPostRepositoriesDB.php - вот она, наша тонкая, изящная Модель,
Только подай-принеси, и ничего больше!

dbh = new PDO("mysql:host=localhost;dbname=test", $user, $pass, array(PDO::ATTR_PERSISTENT => true)); } catch (PDOException $e) { echo "Error!: " . $e->getMessage() . "
"; die(); } }//end __construct public function survey() { $query_view = $this->dbh->prepare("SELECT * from posts"); $query_view->execute(); return $query_view->fetchAll(PDO::FETCH_CLASS, "BlogPostEntitiesPostEntity"); }//end survey }//end class Db

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

Не спорю, во многих случаях удобен фреймворк. Но, посмотрите, Namespace вам ничего не напоминает?
Четкое разделение на классы, строгая, и в тоже время гибкая, полностью подчиненная разработчику иерархия каталогов и классов.
Отсутствие порою такого весомого довеска в виде сотен файлов и классов в виде фреймворка.
Отсутствие прокрустова ложа правил взаимодействия классов и компонентов.

Статья навеяна размышлениями на эту тему Taylor Otwell, автора фреймворка Laravel, за что ему огромное спасибо.
Адрес исходников примера на GitHub.

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

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

Имена: сфера описания данных и алгоритмов

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

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

Приведенный пример - классика, если не обращать внимания на ключевое слово namespace: все, как всегда. Работает второй include. Префикс NameSpaceTwo\ перед именами функций уточняет, из какой вставки берется код.

Если из первой функции убрать ключевое слово global и операцию $iExt = 1; перенести на строчку выше, то про значение переменной 100 не будет знать ни первая функция, ни вторая.

Пространства имен: множество сфер описания

В показанном примере есть общий файл, который использует две вставки. В каждой вставке есть одна и та же функция scCheckName(). Какую из них выбрать, решает программист посредством имени того пространства, которое актуально в нужный момент времени в нужном месте кода.

Тот факт, что одно и то же имя присутствует в общем коде (после слияния вставок) не приводит к ошибке по той простой причине, что каждый файл вставки помечен своим собственным уникальным именем.

В первом файле все, что будет в нем описано, связывается с именем NameSpaceOne. Во втором файле все описания будут привязаны к имени NameSpaceTwo.

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

В этом примере смена имени пространства имен в вызове функции scCheckName() избавила переменную $iExt второго пространства имен от изменения. Именно поэтому в примере специально выделено слово "изменена" - изменение на самом деле не состоялось. Значение переменной осталось прежним.

Тестирование и множественное проектирование

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

  • безопасное тестирование скриптов - путем замены "рабочих" пространств на тестовые аналоги;
  • безопасное проектирование большими коллективами разработчиков - путем предоставления им "индивидуальных" пространств описания элементов.

На самом деле пространство имен имеет гораздо более важное значение. Язык PHP, пространство имен и каждый элемент описания (переменная, константа, объект...) уже очень давно предоставили разработчику возможность самостоятельно манипулировать синтаксисом и семантикой.

Конструкции языка и общее правило современного программирования: "понято" - исполнено - есть противоречие - "белый экран" на профессионального разработчика "не действует".

Многие программисты даже не в курсе, в каком месте искать сообщение PHP об ошибке, когда в браузере ничего нет (чистое белое поле). На определенном этапе своего развития программист мыслит синтаксисом и семантикой PHP, «работает» автоматом и результат: собственный синтаксис и собственная семантика в пределах дозволенного.

Белый экран - сразу однозначная реакция профессионального программиста и ошибка ликвидирована. Зачем тратить время на дебаггер и просмотр лога ошибок?

Объекты, массивы и пространства имен

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

Если использовать массивы объектов, манипулировать идеей стека и последним (первым) элементом массива, то можно получить динамику: объекты сами "решают", как должен работать функционал сайта в зависимости от складывающейся ситуации.

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

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

Объект - это структура и содержание, которые характеризуются единством. Пространство имен - это множество объектов, элементов и связей между ними.

Нельзя проводить эксперименты на работающей системе, но благодаря namespace PHP предоставляет возможность моделировать реальную работающую систему в другом пространстве для целей:

  • дальнейшего развития;
  • тестирования;
  • технического обслуживания и пр.

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

Синтаксис и применение пространства имен

Слово namespace PHP принимает только в первой строчке кода каждого файла. Все описания должны идти только за ним. Синтаксис включает в себя только имя, обозначенное в обычном понимании имени.

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

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

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

Общее правило: namespace - описание и это один файл, use - это импорт пространства в скрипт использования и назначение ему псевдонима (короткой ссылки).

Простой пример автозагрузки классов (объектов)

В задаче имеется объект для манипулирования строками, стилями оформления элементов страницы (описания CSS), объект даты, файловой системы и базы данных. Смысл реализации - создать по этим пяти позициям простые интерфейсы с целью использования нужных возможностей только через методы этих объектов.

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

В коде слева обозначено создание нужных пяти объектов, но где именно они находятся, не указано. В коде справа приведен текст автозагрузчика (основной скрипт), который при загрузке классов (объектов) автоматом подставляет нужный путь до места размещения объекта и расширение файла.php.

Пример множества пространств имен

Библиотека PhpOffice / PhpWord - качественный пример использования сложной иерархии множества пространств имен. Папка элементов содержит практически весь спектр элементов, доступных при формировании документа *.docx (MS Word), другие папки содержат необходимый инструментарий для работы с элементами, параграфами и таблицами.

Собственно, библиотека помещена в папку проекта по той причине, что пространство функциональности PhpOffice / PhpWord требовалось дополнить конкретным инструментарием и в конечном итоге создать собственный вариант аналогичного продукта.

Загрузка множества классов различных пространств имен

Использование PHP namespace autoload, когда необходимо загружать множества классов, а иерархия разработанной системы объектов достаточно сложна и представить ее сложно, приводит к необходимости создания жестких конструкций.

Ориентация разработчика (использующего продукт для продолжения работ) возможна только в контексте семантики (понимания проекта), которая представлена надлежащими сочетаниями слов, отражающих реальное значение и взаимосвязи объектов.

Необходимость применения библиотеки в индивидуальном проекте приводит к решению задачи, как сочетать пространства имен разработчика и авторов PhpOffice / PhpWord. Лучшим является размещение данного продукта (его пространств и объектов) в собственном пространстве проекта.

Существенно отметить, что без модификации пространств имен данного продукта на уровне его абстрактных элементов и загрузки классов обойтись не удастся. Это свидетельствует, что на PHP namespace использование внутренних пространств имен может быть выполнено недостаточно абстрактно и универсально.

Файловая система и локализация пространств

По существу, пространства имен - это «начертание» пути в файловой системе к нужному объекту. Использование имен файлов в качестве имен объектов - естественно и привычно. Использование имен папок в качестве именования пространств имен - объективно.

«Деревянная» организация информации достаточно громоздка в применении и усложняет разработку, но она является естественным представлением для систем объектов.

Проблема состоит в том, что этап разработки представлен определенным редактором кода, который сочетает в себе и видимое представление папок и содержание конкретной папки, но еще нет такого редактора, который бы обеспечивал сквозное движение по объектам и по папкам.

Проблема абстрактности и универсальности

Принято сознанием разработчика и объективно в действительности:

  • дает абстракцию и возможность манипулировать информацией согласно ее реальной семантике;
  • пространства имен отражают положение скриптов, объектов и отчасти смысла проекта в файловой системе

Фактически, соединив абстракцию ООП на имена объектов (файлы) и наложив ее на файловую систему (папки) с адекватным формированием имен namepace (пути + имена), можно управлять формированием пространств имен в процессе исполнения скрипта.

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