Пространства имён в PHP 5

archive view archive save

php-code1 Сегодня мы с Вами в стиле как для полных дэбилов, в хорошем смысле сиго слова, постараемся разобраться в том, что такое пространства имён в 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__;
    }
}

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

<?php 
 
require_once('Liba1.php');
 
echo MYCONST . "\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

<?php 
namespace App;
 
class MyClass {
    public function whoAmI() {
        return __METHOD__;
    }
}

Сам класс MyClass, его методы (функции) и свойства (переменные, константы), будут доступны только из пространства имён App.

Чтобы напрямую использовать MyClass из пространства имён App в нашем исполняемом файле/скрипте, мы должны либо объявить в нём то же "namespace App;" либо использовать "use App\MyClass;":

<?php 
 
//namespace App;
use App\MyClass;
 
require_once('MyClass.php');
 
$obj = new MyClass();
echo $obj->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;

Кто-то может спросить "А накой чёрт нам нужен "Импорт глобального класса"?", - а нужен он для доступа к нему из какого-то пространства имён, например:

<?php 
namespace Vasya;
//use ArrayObject;
 
ini_set('display_errors', 'On'); error_reporting(E_ALL);
 
$array = array('one', 'two', 'three');
 
$arrayObj = new ArrayObject($array);
 
print_r($arrayObj);

Потому как мы находимся в пространстве имён "Vasya", а РНР всегда работает из под текущего пространства имён, то выполнение приведённого выше кода завершится ошибкой "Fatal error: Class 'Vasya\ArrayObject' not found in". Чтобы получить доступ к классу ArrayObject находясь в пространстве имён Vasya нам нужно использовать (раскомментировать) "use ArrayObject;" или претворить имя класса обратным слешем \ArrayObject.

Автозагрузка классов в PHP 5

Нужно помнить, что PHP всегда работает в текущем пространстве имён. Это значит, что если мы объявили пространство имён "namespace Vasya;" и попытались создать объект класса "$obj = new MyClass();", то при использовании функции автозагрузчика "__autoload()" или "spl_autoload_register()" будет выполнена попытка подключить файл по адресу Vasya/MyClass.php. Например:

<?php 
 
// Используем пространство имён Васи
use Vasya;
 
// Автозагрузка классов
spl_autoload_register(function ($class) {
    // convert namespace to full file path
    $class = str_replace('\\', '/', $class) . '.php';
    if (file_exists($class)) {
        require_once($class);
        return true;
    }
    return false;
});
 
$obj = new MyClass();
echo $obj->whoAmI();

Для автоматической загрузки классов функция spl_autoload_register() считается более предпочтительной нежели __autoload(). Функция __autoload() не рекомендуется к использованию и в будущем её поддержка может быть прекращена или она и вовсе может быть удалена. С версии PHP 5.3.0 стало возможным использование безымянных функций (ака "function (){}").

Итоги

Появление в PHP пространств имён однозначно является положительным шагом. Если я где-то протупил, тогда, пожалуйста, поправьте меня своими комментариями.

P.S. Статья написана по просьбам трудящихся, которые не смогли осилить официальную документацию.


Комментарии в блоге
Новое на форуме