Приклади використання namespace в PHP. Простір імен в PHP, роз'яснення. Простір імен: безліч сфер опису

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

Простір імен (англ. namespace) - кілька, під яким мається на увазі модель, абстрактне сховище або оточення, створене для логічного угрупування унікальних ідентифікаторів (тобто імен). Ідентифікатор, визначений у просторі імен, асоціюється із цим простором. Один і той самий ідентифікатор може бути незалежно визначений у кількох просторах. Таким чином, значення, пов'язане з ідентифікатором, визначеним в одному просторі імен, може мати (або не мати) таке ж (а скоріше, інше) значення, як і такий самий ідентифікатор, визначений в іншому просторі. Мови з підтримкою просторів імен визначають правила, що вказують, до якого простору імен належить ідентифікатор (тобто його визначення).

Все ясно? Насправді, все просто. До версії 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); /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.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 = новий 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.

Якщо ви давно використовуєте ООП, то, напевно, зустрічали ситуацію, коли, підключаючи сторонню бібліотеку, у вас траплявся збій через те, що ви вже використовуєте у своєму коді такі самі імена класів, як і в бібліотеці. Особливо це може статися, якщо ви використовуєте такі розповсюджені імена, як "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) - кілька, під яким мається на увазі модель, абстрактне сховище або оточення, створене для логічного угрупування унікальних ідентифікаторів (тобто імен). Ідентифікатор, визначений у просторі імен, асоціюється із цим простором. Один і той самий ідентифікатор може бути незалежно визначений у кількох просторах. Таким чином, значення, пов'язане з ідентифікатором, визначеним в одному просторі імен, може мати (або не мати) таке ж (а скоріше, інше) значення, як і такий самий ідентифікатор, визначений в іншому просторі. Мови з підтримкою просторів імен визначають правила, що вказують, до якого простору імен належить ідентифікатор (тобто його визначення).

Все ясно? Насправді, все просто. До версії 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); /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)

Перед тим, як розглянути, як використовувати namespaces, це є важливою для того, щоб підтвердити, як PHP знають, що namespaced елемент вашого коду є потребою. На пряму аналогію може бути між PHP namespaces and filesystem. Там є три способи доступу до файлу в файловій системі:

  1. Relative file name like foo.txt. This resolves to currentdirectory/foo.txtДе поточнийресурс є директором поточно включений. 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.
Той самий принцип може бути застосований до namespaced elements в PHP. Для прикладу, class name can referred to in three ways:
  1. Unqualified name, або unprefixed class name like $a = new foo(); or foo::staticmethod(); currentnamespace, це resolves to currentnamespace\foo foo. Один міхур: unqualified names for functions and constants буде відповідати Global functions and constants if the namespaced function or constant is not defined. Використовуйте namespaces: fallback до глобальної функції/постійної інформації.
  2. Qualified name, або prefixed class name like $a = новий subnamespace\foo(); or subnamespace\foo::staticmethod();. If the current namespace is currentnamespace, це resolves to currentnamespace\subnamespace\foo. If the code is global, non-namespaced code, this resolves to subnamespace\foo.
  3. Fully qualified name, або prefixed name with global prefix operator like $a = new \currentnamespace\foo(); or \currentnamespace\foo::staticmethod();. Це завжди resolves to 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::статичнийметод (); // 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
?>

Зверніть увагу, що для користування будь-яким кузовом класу, функцією або постійною, повністю зображений name може бути використаний, так як \strlen() or \Exception or \INI_ALL. ?>