Домой Windows 7 PHP NameSpace — как же все-таки его готовить? Пространства имен в PHP, разъяснение Что такое namespace php

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

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 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 .

Если вы давно используете ООП , то, наверное, встречали ситуацию, когда, подключая стороннюю библиотеку, у вас случался сбой из-за того, что вы уже используете в своём коде такие же имена классов, как и в библиотеке. Особенно это может случиться, если вы используете такие распрастранённые имена, как "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;
}
?>

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

Недавно инкапсулировал свой проект в 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 >= 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 . ?>

Новое на сайте

>

Самое популярное