Php class autoloader namespace

PHP Namespace

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

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

Все ясно? На самом деле все просто. До версии 5.3 в php существовало всего два пространства — глобальное(в котором выполнялся ваш основной код) и локальное(в котором определялись переменные функций).
image
С версии 5.3 все изменилось. Теперь можно определить свое пространство имен, в котором будут существовать ваши классы методы и т.д.
image
Надеюсь стало немного понятнее.

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

Читайте также:  Check parse in java

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

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

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

Рекомендуется объявлять каждое пространство имен в отдельном файле. Хотя можно и в одном, но это строго не рекомендуется!
Теперь переместимся в третий файл, в котором будет функционировать наш основной скрипт
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__ которая содержит имя текущего пространства.

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

  public static function autoload($file) < $file = str_replace('\\', '/', $file); $path = $_SERVER['DOCUMENT_ROOT'] . '/classes'; $filepath = $_SERVER['DOCUMENT_ROOT'] . '/classes/' . $file . '.php'; if (file_exists($filepath)) < if(Autoloader::debug) Autoloader::StPutFile(('подключили ' .$filepath)); require_once($filepath); >else < $flag = true; if(Autoloader::debug) Autoloader::StPutFile(('начинаем рекурсивный поиск')); Autoloader::recursive_autoload($file, $path, &$flag); >> public static function recursive_autoload($file, $path, $flag) < if (FALSE !== ($handle = opendir($path)) && $flag) < while (FAlSE !== ($dir = readdir($handle)) && $flag) < if (strpos($dir, '.') === FALSE) < $path2 = $path .'/' . $dir; $filepath = $path2 . '/' . $file . '.php'; if(Autoloader::debug) Autoloader::StPutFile(('ищем файл ' .$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

  function sayName($name) < echo 'Привет ' . $name; >static function sayOther() < echo 'статичный вызов'; >> > 
 sayName('test'); //а можно так test\sayName('test2'); //или так $obj::sayName('test'); //а можно так test::sayName('test2'); 

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

Источник

Оцените статью