Статьи

Пространства имен PHP

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

Зачем использовать пространства имен?

Представьте, что вы работаете в небольшой компании, в которой мало сотрудников. Говоря о сотруднике, вы называете его по имени. После исключительно успешного года ваш начальник решает удвоить количество сотрудников. Внезапно, когда вы упоминаете «Том», люди больше не уверены, к кому вы обращаетесь, поскольку в офисе сейчас есть несколько Томов. Чтобы различать их, вы также начинаете использовать их фамилии.

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

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

До того, как пространства имен стали доступны, разработчики эмулировали их в объектно-ориентированном коде, добавляя префиксы классов каждого компонента к имени компонента. Например, одним из стандартов было объединение имен компонентов и классов с помощью подчеркивания; почтовый класс в компоненте блога был назван Blog_Mail . Эта практика привела ко многим длинным, а иногда и запутанным именам классов. Рассмотрим имя класса в PHPUnit_Framework_MockObject_Matcher_StatelessInvocation PHPUnit, PHPUnit_Framework_MockObject_Matcher_StatelessInvocation . Это, очевидно, не идеально, поэтому программисты нуждались в надлежащей поддержке пространств имен в PHP.

Определение пространств имен

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

 <?php namespace MyNamespace; // ... 

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

 <?php namespace MyNamespace { // ... } 

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

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

 <?php namespace MyProject\Blog\Admin; 

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

 <?php namespace MyProject\Blog; // following definitions are part of the MyProject\Blog namespace // ... namespace MyProject\Store; // following definitions are now part of MyProject\Store // ... 

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

 <?php namespace My\Project { // My\Project namespace // ... } namespace { // Global namespace // ... } 

Ссылка на идентификаторы пространства имен

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

  1. Полностью квалифицированное имя
    Полное имя похоже на абсолютный путь в файловой системе. Это полное имя идентификатора; поэтому нет никакой двусмысленности относительно того, на какой идентификатор ссылаются. Полностью определенные имена начинаются с обратной косой черты. Например, My\Foo\Bar ищет класс Bar в пространстве имен My\Foo .
  2. Квалифицированное имя
    Полное имя похоже на относительный путь в файловой системе. Он содержит только часть имени и разрешается относительно текущего пространства имен. Например, Foo\myFunction() в пространстве имен MyBaz в \My\Baz\Foo\myFunction() .
  3. Неквалифицированное имя
    Неквалифицированное имя идентично квалифицированному имени, за исключением того, что оно относится только к текущему пространству имен, а не к каким-либо подпространствам имен. Например, getPosts() в пространстве имен My\Foo\Blog Blog\getPosts() в Blog\getPosts() . Если функция или константа не найдены в текущей области видимости, PHP не будет искать \My\Foo\getPosts() , а просто разрешит идентификатор в глобальном пространстве имен.

Давайте посмотрим на пример. file1.php содержит пару имитационных определений имен пространства \MyProject\Blog .

 <?php namespace \MyProject\Blog; class myClass {} function myFunction() {} 

Теперь file2.php объявляет пространство имен file1.php , включает file1.php и определяет ложные определения, которые, казалось бы, конфликтуют. Определения не, тем не менее, потому что они живут в отдельных пространствах имен. Затем файл продолжает показывать примеры того, как разрешаются полностью квалифицированные и неквалифицированные имена.

 <?php namespace \MyProject; require_once "file1.php"; class myClass {} function myFunction() {} // fully-qualified names \MyProject\myFunction(); \MyProject\Blog\myFunction(); // qualified name \Blog\myFunction(); //resolves to \MyProject\Blog\myFunction(); // unqualified name $test = new myClass(); // resolves to \MyProject\myClass myFunction(); // resolves to \MyProject\myFunction 

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

 <?php namespace \Foo\Bar; function file_exists($filename) { return true; } // Incorrect: "Fatal error: Class '\Foo\Bar\ArrayObject' not found..." $obj = new ArrayObject(); // Correct $obj = new \ArrayObject(); // Doesn't need backslash; resolves to native function echo strlen("Hello, world!"); // Resolves to dummy function, \Foo\Bar\file_exists() echo file_exists('non-existent-file'); // True // Resolves to real function echo \file_exists('non-existent-file'); // False 

Ключевое слово use

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

Вот пример:

 <?php use \Very\Long\Namespace; use \Another\Long\Namespace\ClassName; // resolves to \Very\Long\Namespace\aFunction(); Namespace\aFunction(); // resolves to \Another\Long\Namespace\ClassName $obj = new ClassName(); 

Только неквалифицированные и квалифицированные имена затрагиваются псевдонимами; Полные имена не являются. Поэтому следующие псевдонимы не будут затронуты:

 <?php $obj = new \ClassName(); 

Чтобы указать конкретный псевдоним, используйте ключевое слово as затем псевдоним.

 <?php use \Very\Long\Namespace as MyNamespace; // resolves to \Very\Long\Namespace\ClassName $obj = new MyNamespace\ClassName(); 

Для удобства PHP позволяет разделить несколько объявлений пространства имен запятыми.

 <?php use \Very\Long\Namespace as MyNamespace, \Another\Long\Namespace\ClassName; 

Чтобы явно использовать текущее пространство имен и избежать псевдонимов, используйте ключевое слово namespace перед именем идентификатора.

 <?php // resolves to current namespace, not \Another\Long\Namespace\ClassName $obj = new namespace\ClassName(); 

Динамические Особенности

PHP также предлагает некоторую поддержку для динамического использования пространств имен. Магическая константа __NAMESPACE__ определяется PHP во время компиляции и содержит текущее пространство имен в виде строки. В глобальном пространстве имен __NAMESPACE__ содержит пустую строку.

На идентификаторы пространства имен можно динамически ссылаться точно так же, как на нормальные идентификаторы, за одним исключением: на идентификаторы можно ссылаться только с использованием полностью определенных имен. Например:

 <?php $class = '\MyProject\Blog\MyClass'; $obj = new $class(); 

Вы всегда должны избегать обратной косой черты, когда они заключены в двойные кавычки, поскольку определенные комбинации символов имеют особое значение. Например, «n» — символ новой строки, «t» — символ табуляции и т. Д. Несоблюдение этого требования может привести к неожиданным результатам. Например, следующий код не будет работать должным образом:

 <?php // "\n" in "\newFunction" seen as newline $function = "\MyProject\Blog\newFunction"; $function(); // Fatal error: "Call to undefined function..." 

Правильно экранированная строка "\\MyProject\\Blog\\newFunction" .

Резюме

Пространства имен — это мощная языковая функция, которую можно использовать для эффективной группировки компонентов в приложении, не опасаясь коллизий. В этой статье рассматриваются причины, по которым вам следует использовать пространства имен и синтаксис для их определения и использования. Вы также увидели, как ключевое слово use позволяет создавать псевдонимы пространств имен и как динамически использовать классы и функции пространства имен. Теперь вы должны иметь полное представление о пространствах имен и быть готовыми начать использовать их в своих собственных приложениях.