что такое пространство имен php
Пространства имен в PHP, разъяснение
Прим.пер.: Я в курсе, что на момент перевода актуальная версия PHP — 5.5, а также что есть мудрая книга мануал. Но мне показалось интересным, то как автор преподносит namespace функционал, возможно кому-то из тех, кто только постигает азы (да и не только, есть немало бородатых разработчиков, остановившихся на PHP 5.2), статья поможет проникнуться. Ходор.
Глобальное пространство имен
Вот такой, очень простой класс:
Ничего особенно, как видите, и если вы хотите использовать его, просто сделайте так:
Хорошо, хорошо, извини. Суть в том, что мы можем думать об этом классе, как находящимся в глобальном пространстве имён.Я не совсем уверен, что это правильный термин, но на мой взгляд это звучит вполне уместно. Собственно, это значит то, что класс не принадлежит никакому пакету, просто обычный класс.
Простое использование пространств имён
Давайте создадим еще одного Эддарда, рядом с тем, глобальным.
Здесь у нас очень похожий класс с одним небольшим изменением, добавлена директива пространства имен. Строка namespace Stark; говорит PHP что мы работаем в пространстве имен Stark и любой код (объявление классов, функций, переменных и т.д.) будет относиться к нему.
Итак, нам нужно создать нового Эдда, если вы решили что это нужно сделать вот так:
То нет, это не так. Здесь мы получаем экземпляр класса из первого примера, который мы создали ранее. Не тот, в пространстве имен Stark. Давайте попробуем создать экземпляр Эддарда Старка.
Для создания экземпляра класса нам нужно предварить имя класса префиксом из названия пространства имен, которому класс принадлежит, а в качестве разделителя использовать обратную косую черту. В итоге у нас есть экземпляр именно того класса, что нам нужен. Разве это не волшебно?
К слову сказать, пространства имён могут образовывать сколь угодно сложную иерархию, используя столько уровней, сколько потребуется. Например:
Теория относительности
Помните, как я сказал вам, что PHP всегда работает относительно текущего пространства имен. Давайте взглянем на это в действии:
Добавив директиву пространства имён, мы дали понять PHP, что мы находимся в пространстве имён Stark. Так как именно в нем мы определили класс Eddard, то именно его мы и получим. Видите — все относительно.
Сейчас, когда мы изменили пространство имён, у нас возникла одна маленькая проблема. Есть идеи, о чем я? А как нам теперь получить наш оригинальный класс Eddard? Ну тот, который в глобальном пространстве?
К счастью в PHP есть трюк, который позволит нам решить эту проблему — просто добавив \ к имени класса.
Видя ведущий слеш PHP понимает, что нужно выглянуть за пределы текущего namespace и создает экземпляр нужного нам класса.
А сейчас включи свое воображение. Представь, что у нас есть класс из другого пространства имен, названный Tully\Edmure. Сейчас нам нужно использовать его внутри пространства Stark. И как нам это сделать?
И снова нам пришлось использовать обратный слеш, чтобы перейти к глобальной видимости, прежде чем создать экземпляр класса в пространстве Tully.
Вообще, ссылаться вот так на классы из других пространств имен, используя полную иерархию в названии, может быть довольно утомительно. Но к счастью, есть возможность сделать ярлык, давайте посмотрим:
А, еще один маленький трюк! Мы можем дать нашим импортируемым классам прозвища:
Давая Daenerys из пространства Dothraki прозвище Khaleesi, мы можем использовать оба класса Daenerys. Довольно удобно, там мы можем использовать все необходимые классы в нашем приложении.
Структура
Пространства имен также могут помочь нам в организации нашего кода. Позвольте, я продемонстрирую.
Скажем, я хочу создать библиотеку с открытым исходным кодом. Мне бы очень хотелось, чтобы другие могли использовать мой код, это было бы здорово! Беда в том, что имена классов в моем коде конфликтовали с собственным приложением пользователя моей библиотеки. Это было бы ужасно неудобно. Вот как я решу эту проблему:
Здесь я использовал свое имя, чтобы показать, что код принадлежит мне, и отделить свой код от кода пользователя моей библиотеки. Внутри базового пространства имен я создал структуру классов в соответствии с их иерархией.
Начав использовать composer, вы узнаете, как использовать пространства имён для упрощения автозагрузки кода. Я настоятельно рекомендую вам взглянуть на этот полезный механизм.
Недостатки
По правде говоря, я чувствую себя немного виноватым за то, что назвал этот подзаголовок «Недостатки». То, о чем я собираюсь говорить, на самом деле ошибкой не является.
Дело в том, что в других языках функционал пространств имён реализован похожим образом, и при этом языки обеспечивают дополнительный функционал для взаимодействия с пространствами имён.
В Java, например, вы можете импортировать несколько классов в текущее пространство имен, используя оператор импорта. В Java, import является аналогом use и он использует точки, чтобы отделить вложенные пространства имен (или пакеты). Вот пример:
В PHP у вас так не выйдет. Вы должны импортировать каждый класс в отдельности. Извините. Собственно, почему я извиняюсь? Идите и жалуйтесь команде разработчиков PHP, но я прошу вас — будьте вежливы. Они сделали много интересного в последнее время.
Вот изящный трюк, чтобы немного сгладить озвученную проблему. Представьте себе, что у нас есть структура классов из предыдущего примера. Мы можем взять часть подпространства и дать ему псевдоним.
Это может быть полезным при использовании большого числа классов. Добра всем!
Все пожелания и предложения с радостью приму в личку, спасибо.
Что такое пространство имен php
(PHP 5 >= 5.3.0, PHP 7, PHP 8)
Ниже приведён пример трёх вариантов синтаксиса в реальном коде:
namespace Foo \ Bar \ subnamespace ;
const FOO = 1 ;
function foo () <>
class foo
<
static function staticmethod () <>
>
?>
namespace Foo \ Bar ;
include ‘file1.php’ ;
const FOO = 2 ;
function foo () <>
class foo
<
static function staticmethod () <>
>
/* Неполные имена */
foo (); // определяется как функция Foo\Bar\foo
foo :: staticmethod (); // определяется как класс Foo\Bar\foo с методом staticmethod
echo FOO ; // определяется как константа Foo\Bar\FOO
/* Полные имена */
subnamespace \ foo (); // определяется как функция Foo\Bar\subnamespace\foo
subnamespace \ foo :: staticmethod (); // определяется как класс Foo\Bar\subnamespace\foo
// c методом staticmethod
echo subnamespace \ FOO ; // определяется как константа Foo\Bar\subnamespace\FOO
/* Абсолютные имена */
\ Foo \ Bar \ foo (); // определяется как функция Foo\Bar\foo
\ Foo \ Bar \ foo :: staticmethod (); // определяется как класс Foo\Bar\foo с методом staticmethod
echo \ Foo \ Bar \ FOO ; // определяется как константа Foo\Bar\FOO
?>
Пример #1 Доступ к глобальным классам, функциям и константам из пространства имён
function strlen () <>
const INI_ALL = 3 ;
class Exception <>
$a = \ strlen ( ‘hi’ ); // вызывает глобальную функцию strlen
$b = \ INI_ALL ; // получает доступ к глобальной константе INI_ALL
$c = new \ Exception ( ‘error’ ); // Создаёт экземпляр глобального класса Exception
?>
Как использовать пространства имен в PHP, Часть 1: Основы
Предисловие: На Хабре уже публиковались несколько статей, посвященных пространству имен в PHP (все ссылки на них я привожу в приложении). Однако, этот интересный и полезный вопрос был раскрыт не полностью. Поэтому я привожу перевод первой из трех статей по данной теме (остальные переведу в ближайшее время). P.S. Статья для начинающих
Пространства имен (namespaces) — это одно из самых значительных изменений в PHP 5.3. Они будут хорошо знакомы С# и Java разработчикам, и, вероятно, они изменят к лучшему структуру PHP-приложений.
Почему мы нуждаемся в пространстве имен?
Поскольку размер библиотеки Вашего PHP кода растет, возрастает и риск случайного переопределения функции или имени класса, которые были объявлены ранее. Проблема усугубляется, когда Вы пытаетесь добавлять сторонние компоненты или плагины; что будет, если два или более наборов кода будут выполнять классы «Database» или «User»?
Ранее, единственным решением были длинные имена классов/функций. Например, WordPress добавлял к каждому имени префикс «WP_». Zend Framework обычно дает детально описывающие названия, что приводит к длиннющим именам классов, таким как Zend_Search_Lucene_Analysis_Analyzer_Common_Text_CaseInsensitive.
Проблемы совпадения имен снимаются введением пространств имен. PHP константы, классы и функции могут быть сгруппированы в библиотеки пространств имен (namespaced libraries).
Как определяются пространства имен?
По умолчанию, все имена констант, классов и функций размещены в глобальном пространстве — как это и было до того, как PHP стал поддерживать пространства имен.
В коде, пространства имен определяются с помощью единственного слова namespace в самом начале Вашего PHP файла. Это слово должно быть самой первой командой (за исключением declare) и ни не-PHP код, ни HTML, ни даже пробел не должен предшествовать этой команде, например:
Весь код, следующий за этими строками, будет относиться к пространству имен «MyProject». Невозможно вкладывать в него другие пространства имен, или определять более чем одно пространство имен для одной и той же части кода (поскольку распознано будет лишь последнее объявление пространства имен, предшествующие же — игнорируются). Тем не менее, Вы можете определить различные пространства имен в одном и том же файле, например:
Но, хотя это и возможно, я бы не советовал делать так: будьте благоразумны, определяя только одно пространство имен для каждого файла.
Подпространства имен (Sub-namespaces)
Вызов кода, относящегося к пространству имен
В файле с именем lib1.php мы определим константу, функцию и класс в пределах пространства имен App\Lib1:
lib1.php
Теперь мы можем включить этот код в другой PHP файл, например:
myapp.php
Никаких пространств имен не определено в файле myapp.php, поэтому код существует в глобальном пространстве. Любая прямая ссылка на MYCONST, MyFunction или MyClass вызовет сбой, поскольку они существуют только в пространстве имен App\Lib1. Чтобы вызвать код из lib1.php, мы можем добавить префикс \App\Lib1, чтобы определить полное квалифицированное имя. На выходе, когда загрузим myapp.php, мы получим следующий результат:
Полные квалифицированные имена могут становиться достаточно длинными; вместе с тем, существует несколько очевидных преимуществ в определении длинных имен классов, наподобие App-Lib1-MyClass. Поэтому, в следующей статье, мы обсудим использование псевдонимов (aliasing) и разберемся как PHP разрешает имена пространств имен.
Что такое пространство имен php
Начиная с версии 5.3 в PHP были добавлены пространства имен. Должен сказать, что большинство современных языков программирования уже довольно давно поддерживают этот функционал, так что можно сказать, что PHP немного задержались. Тем не менее, давайте рассмотрим как же это нововведение повлияло на разработку приложений.
Пространства имен в PHP помогают обойти это ограничение, более того, мы можем создать сколько угодно классов с одним названием. Также они позволяют группировать вместе логически связанные участки кода.
Рассмотрим стандартный класс.
Глобальное пространство имен
Вот пример простого класса:
Ничего особенного. Вот пример его использования:
Итак, этот класс доступен в «глобальном» пространстве имен. Может я немного путаю термины, но идея, надеюсь, понятна. Таим образом, этот класс существует вне пространства имен, то есть, опять-таки, обычный класс.
Простое пространство имен
Создадим еще один класс по соседству с первым:
Теперь, снова используем класс User.
Мы получим экземпляр первого класса. А вот таким образом можно создать объект класса из нужного нам пространства имен:
Отмечу, что глубина вложенности пространств практически неограниченна. Например:
Теория относительности
PHP всегда работает относительно текущего пространства имен. Рассмотрим пример:
Но таким образом мы получили побочный эффект, не догадываетесь о чем я? А как же мы создадим первый класс User, тот что без указания пространства?
Существует маневр для использования классов принадлежащих к глобальному пространству. Надо просто добавить обратный слеш \ к имени класса.
При помощи директивы as мы задали классу Auth\Member имя AuthMember и теперь можем к нему обращаться по этому имени. Довольно удобно, не так ли? Такой же способ можно применить при использовании одноименных классов, например:
Таким образом, в нашем скрипте присутствуют два одноименных класса, но мы их разделили при помощи директивы as. То есть мы избежали конфликта имен.
При помощи use вы можете подключить сколько угодно классов.
Структура
Пространства имен помогают нам не только избежать конфликтов, но и структурировать наш проект. Приведу пример: допустим, я создаю библиотеку и при этом не хочу причинить вреда уже написанному коду пользователя.
Так можно обойти все связанные с этим проблемы:
Мы использовали своё имя для пространства имён, чтобы разъединить код библиотеки и код пользователя, который будет её использовать. Внутри корневого пространства имен своей библиотеки я использую другие подпространства для логического деления функционала.
Ограничения
Здесь я расскажу о недостатке функционала пространства имен. Дело в том, что в других языках программирования пространства имен реализованы подобным способом, и все они имеют отличительную способность.
В PHP такой возможности нет. Каждый класс приходится подключать отдельно. Просьба жалобы отправлять не в мой адрес, а в адрес разработчиков PHP. Только аккуратно, все-таки они постоянно добавляют отличные возможности в свой язык. Но и тут я покажу вам небольшую лазейку. Допустим, структура вашего проекта выглядит следующим образом:
Дадим новое имя подпространствам и будем обращаться к ним так:
Думаю, это упростит вам работу при использовании большого количества классов из одного пространства имен. Спасибо за внимание!
Использование пространства имен: основы
Ниже приведен пример трех вариантов синтаксиса в реальном коде:
namespace Foo \ Bar \ subnamespace ;
const FOO = 1 ;
function foo () <>
class foo
<
static function staticmethod () <>
>
?>
namespace Foo \ Bar ;
include ‘file1.php’ ;
const FOO = 2 ;
function foo () <>
class foo
<
static function staticmethod () <>
>
/* Неполные имена */
foo (); // определяется как функция Foo\Bar\foo
foo :: staticmethod (); // определяется как класс Foo\Bar\foo с методом staticmethod
echo FOO ; // определяется как константа Foo\Bar\FOO
/* Полные имена */
subnamespace \ foo (); // определяется как функция Foo\Bar\subnamespace\foo
subnamespace \ foo :: staticmethod (); // определяется как класс Foo\Bar\subnamespace\foo
// c методом staticmethod
echo subnamespace \ FOO ; // определяется как константа Foo\Bar\subnamespace\FOO
/* Абсолютные имена */
\ Foo \ Bar \ foo (); // определяется как функция Foo\Bar\foo
\ Foo \ Bar \ foo :: staticmethod (); // определяется как класс Foo\Bar\foo с методом staticmethod
echo \ Foo \ Bar \ FOO ; // определяется как константа Foo\Bar\FOO
?>
Пример #1 Доступ к глобальным классам, функциям и константам из пространства имен
function strlen () <>
const INI_ALL = 3 ;
class Exception <>
$a = \ strlen ( ‘hi’ ); // вызывает глобальную функцию strlen
$b = \ INI_ALL ; // получает доступ к глобальной константе INI_ALL
$c = new \ Exception ( ‘error’ ); // Создает экземпляр глобального класса Exception
?>