войти зарегистрироваться

PHP whois

индекс
169,28

Пространство имён в php 5.3 и php 6

Пространство имён (namespace/package) знакомо java и c# программистам, теперь доступно и в php. Нужно оно для того, что-бы не писать длинные перефиксы к названиям классов, как сейчас делается в Zend, PEAR и других библиотеках и платформах для совместимости.

Вместо этого классы, функции, интерфейсы (абстрактные классы) и константы могут быть объединены в одно пространство имён. Глобальные переменные в это пространство не входят.

Простой пример

Определяется пространство ключевым словом namespace

//определяем класс в пространстве
namespace MyCMS::Core;
class System{}

Использование этого класса в третьих библиотеках осуществляется ключевым словом use

require_once('mycms/core.php');
use MyCMS::Core::System; //импортируем только заданный класс
$objSystem=new System;

Как вы уже догадались, разделитель :: работает так же как и вызов статических методов, разделяя уровень пространства имён и конкретный класс. Уровень вложённости пространств можно использовать наряду с модульностью библиотеки, например реализовать пространства Database::MySQL::Adapter и Database::Oracle::Adapter.

Новые возможности и новые проблемы

Если в пространстве имён имя класса перезаписывает ранее объявленный глобальный класс или функцию, то к нему по прежнему можно обратится через ::SomeClassName, однако не зная к какой именно реализации программист обращается может вызвать проблемы. Например можно переобъявить стандартные php функции, поменять sin() и cos() местами, что-бы кому-то жизнь мёдом не казалась.

Для отладки существует рабочая константа __NAMESPACE__.

С двоеточием возникает и проблема неоднозначности:

A::B() // вызов функции B из namespace A
A::B() // вызов статичного метода B у класса A

Читайте по теме:

Оригинал

комментарии (78)

  • Не боян-ли?

    По-моему лучше в оригинале прочитать - например тут - http://ilia.ws/files/phpquebec_php53.pdf
  • Спасибо, приятная статья. Многим полезно будет новое узнать.
    Один только вопрос - почему на в блоге PHP? Перенесли бы.
  • И вопрос в догонку - может автор знает какие-то ньюансы работы с неймспейсами в 5.3 и 6 версии, все-таки лично мне хочется больше уже ньансов, а не простого переписывания того, что написано в принципе везде про появление неймспейсов в новых версиях..

    Согласен, вопрос актуальный, но нужно как-то больше конкретики.
    • увы, рабочий хостинг всё ещё на 5.2.5 стоит
      • Очень жаль :(
      • Установите 5.3 в качестве cgi... И будет счастье ;-)
  • Мда, чет они перемудрили с двумя двоеточиями. Неужели сложно было придумать новое обозначение? типо >> или три двоеточия)
    • А разве >> не бинарный сдвиг?
      • точняк, вылетело из головы) тогда :>:
    • точку надо!! как в нормальных ЯВУ.
    • зачем? двоеточие на эту роль хорошо подходит, в то же время, неймспейсы - имхо недостаточный повод чтобы вносить в язык новый синтаксический элемент.

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

      и два: в чем концептуальная разница между статическим методом и функцией в неймспейсе, а? (-:

      А, ну и ещё: в питоне, например, для обращения к методам объектов и к объектам из ругого пространства имён тоже используется одинаковый синтаксис (точка) и ничего, никто пока не умер (-:
      • Метод связан с классом или объектом, тогда как функция от объекта не зависит
        http://en.wikipedia.org/wiki/Method_(computer_science)
        http://en.wikipedia.org/wiki/Function_(computer_science)
        • не-не. я спрашивал конкретно про статические методы.

          с точки зрения вызывающего в чем разница?

          насколько важно мне знать чем концептуально отличаются класс C и неймспейс N в этих примерах:

          C::get_instance();
          N::get_instance();
          • self
            как я понимаю, в неймспейсах он не доступен
            • снаружи когда я вызываю это, зачем мне знать как оно внутри работает?
          • 1. В статичных методах при наследовании насколько я помню можно обращаться к родительским методам через parent::метод
            2. Обращение к статичным параметрам класса (правда с наследием там вроде баги были)
            Как я понимаю c namespace такого не проделаешь, хотя выглядит оно одинаково и вероятно реализуется тоже.
            • 1. снаружи когда я это вызываю, зачем мне знать как оно работает внутри?
              2. см. п. 1

              Естественно, если я хочу наследоваться, то разница есть и я вынужден буду узнать как оно устроено, однако вопрос стоял не так.
    • Это преемственность С++
  • в C++ такая же неоднозначность существует. И ничего, живут.
    • Проблема надуманна, это факт. Просто такое положение дел не привычно в PHP, так, как неймспейсов до этого вообще не было, поэтому многих смущает то, как это выглядит и выдумывают проблему на пустом месте.
  • НЛО прилетело и опубликовало эту надпись здесь.
  • интересно, когда версии с поддержкой неймспейсов станут распространены на различных хостингах, имена классов в Zend Framework остануться такими же, или все переведут на неймспейсы...
    • а о совместимости ты подумал?
      • ZF активно развивается, нельзя тащить с собой кучу старого кода только для совместимости, а то как у microsoft получится. конечно, в случае таких тяжелых нововведений нужно дать достаточно времени разработчикам на переход
        • вот именно, что достаточно, а это растянется очень надолго..
        • префиксы в именах старых классов ради обратной совместимости - не такое уж большое зло, как мне кажется.
  • require_once — моветон в php 5+, есть SPL. А так ниче нового не сказали, анонс namespace был давно.
    • Вы имеете ввиду autoload? Помоему он тоже require_once использует.
      • Он использует то, что напишет программист. __autoload() - это просто функция, а не магия какая-то :)

        function __autoload($className) {
        $fileName = $className.'.class.php';
        require PATH_ROOT."classes/".$fileName;
        }

        Простейший пример.
        • Я такую конструкцию и использую, вот и интересуюсь - можно ли и как попроще (и куда уж проще)?
          • Тогда я не совсем понял, что значит "Вы имеете ввиду autoload? Помоему он тоже require_once использует. ".

            Ответ на Ваш вопрос - "а куда еще проще?".
            • Я не складирую все файлы в одну папку если вы подразумеваете autoload по умолчанию
              • Ну на самом деле я не подразумевал, у меня как раз в разных папках.

                Я делаю это приблизительно так:

                function __autoload($className) {
                $locations = array('forum', 'fun', 'gallery', 'leecher', 'soap', 'common');

                $fileName = $className.'.class.php';
                foreach ($locations as $path) {
                if (file_exists(PORTAL_PATH_ROOT."classes/".$path."/".$fileName)) {
                require PATH_ROOT."classes/".$path."/".$fileName;
                break;
                }
                }
                }

                Вы же можете массив сделать в конфиге или из базы выбирать, в зависимости от того, как храните информацию о модулях.
                • PORTAL_PATH_ROOT = PATH_ROOT - плохо отредактировал.
                • Видите - всё правильно, вы тоже require используете, а что Xobb имел ввиду я не понимаю..
                  • Я имею ввиду SPL-register. Оно позволяет написать правило загрузки классов. Наглядный пример здесь. Да, в принципе используется require, но только один раз и больше его в коде использовать не надо. Своим комментарием я имел ввиду, что если мы уж настолько продвинуты чтобы использовать namespace то было б хорошо научится и делать autoload.
                    • Спасибо за информацию! Давно пишу на php, а про эту фичу не знал. Буду разбираться, надоело писать в стиле php4
                    • По поводу spl_autoload_register, я его использовал одно время, но потом отказался в пользу статичного(единственного) автолоада с проверками дирректорий и наличия файлов, поскольку динамическая регистрация уж очень много ресурсов жрет.
                    • Не понимаю, чем require плох. Да, автолоад, несомненно, рулит, но, имхо, это какая-то глупая религия - сокращать количество require до 1 в проекте... Конечно, 500 require это тоже перебор, но autoload так или иначе выполняет столько же require(достаточно глянуть по профайлеру), хоть они и сосредоточены в одном методе.
                      • Все просто - уменьшение сложности. Тебе не надо задумыватся о том как подключать, где и по какому принципу классы, ты решаешь это все зарание и больше не задумываешься.
                        • Хм, тут такие хитрые коды пишут, лишь бы не писать лишние require... Может я читаю как-то не так, но мне кажется, что слишком категорично высказано, что на весь проект должен быть 1 require и тот в автолоаде... Я и сам активно юзаю autoload, но не вижу смысла сокращать количество require до 1-2, имхо, разумный предел - 5-10, хотя всё зависит от архитектуры проекта.
                    • А разве исполнение php-файлов ограничивается только подключением классов?
                      • Простите меня пожалуйста, вы сноб и приебываетесь.
                        require_once('mycms/core.php');
                        use MyCMS::Core::System; //импортируем только заданный класс
                        $objSystem=new System;

                        Мое мнение относится только к коду выше. И никуда больше. Да, я сам использую require, когда мне надо подключить левый код к своему проекту, который не следует API фреймворка, на котором я работаю.
                        • Несомненно можно было бы разобрать ваш код и, возможно, даже признать свою неправоту. Но, к сожалению, вынужден завершить наш диалог пожеланием вам отправится к определенной матери. спасибо.
    • Да ну..для классов уже давно используется __autoload, а если пишут на функциях все, то кто уж им виноват..
    • Хм, почему моветон?
  • Уважаемый Ларри Уолл - чтото мне это все напоминает =)
    • Вас так пугают двоеточия?
      • Наоборот, Уважаемый! Радуют =) Изобретение велосипеда направляется к своему логическому завершению =)
    • Да, хорошо, что не стали изобретать велосипед. PHPшникам легче будет понимать код на Perl.
      • Как правило для хороших PHPшников нет проблемы понимать Perl, посколько до PHP они писали на Perl :)
  • require_once('mycms/core.php');
    use MyCMS::Core::System; //импортируем только заданный класс

    А разве require_once не "импортировало" уже все то, что было в mycms/core.php?
    • use автоподстановку делает.
      Как я понимаю, new Class() будет на самом деле делать new MyCMS::Core::System::Class()...
      Имхо, бесполезная штука — нагляднее использовать полное название неймспейса или хотя бы алиас...
      • во всех языках сделали такую бесполезную штуку. вот глупцы.
        • Вы о чём? Это чтобы конфликтов имён классов в разных неймспейсах небыло. Ну и чтобы, используя много классов из неймспейса, не писать много раз подряд всю вереницу вложености NS.
          • я о сарказме на тему того, на что отвечал
            • Пардон, не сразу уследил...
        • я только про use ;) и я ступил, признаю, сам ведь буду использовать...
  • Хотелось бы, например, знать
    • как можно в автолоаде узнать запрашиваемый неймспейс или как можно (и можно ли) делать локальные (в рамках одного неймспейса) автолоады
    • можно ли перемещаться по иерархии неймспейсов? потому как если нет, то лучше было бы сделать вложенные классы для static обращений
    • как понять фразу мануала «К примеру, если пространство имён A::B::C импортировано, new C() будет транслировано как new A::B::C().», если new A::B::C() обращается к неймспейсу A::B
    • По поводу первого: в автолоад имя класса приходит полностью My::Namespace::For:MyClass.
      • я подозревал, спасибо )
  • Хороший язык - php, сейчас правда перешел с него на Java и уже плотно занимаюсь только ею, но такое чувство что концептуально (т.е. за исключением некоторых моментов синтаксиса и конечно же рантайма) между ними скоро не будет различий ;)
    • боюсь, что основное концептуальное различие - строгая типизация, навряд ли будет добавлено в PHP
      • А вот это бооольшой вопрос )) На крайняк будет 2 явы - со строгой типизацией и без строгой типизации )))
        • вообще-то уже есть, в виде Groovy )
          • Не, ну груви это все же не php ))
            • это сильно круче :) так сказать, ява мутирует в питона и руби
      • Нашли чего бояться :)
  • пространства имен штука очень полезная. Но, как это обычно бывает у разработчиков PHP, хотели как лучше - получилось как всегда: какой то корявый синтаксис System::Core. А ведь можно было сделать очень просто и красиво:


    namespase System.Core
    {
        class MyClass()
        {}
    }
    • к сожалению, точка уже давно забита под конкатенацию строк :(
      • уверяю, нет никакой технической проблемы, что точка конкатенирует строки. На месте имени нэймспэйса же не expression.

        А в принципе точка как конкатенация строки — бред полный, плюс куда лучше был бы.
        • Хватит говорить со мной как с разработчиком пхп!
      • ну в общем, дело не в точке, а в единообразности - содержимое класса находится между фигурными скобками{}, так почему же сам класс не поместить в пространство имен между {}.
  • Постепенно php превращается в perl. Это не может не радовать. Так глядишь и оператор =~ появится вместно ужасных preg_*
    • Хм, Namespace'ы двигают PHP в сторону Perl? Сомневаюсь, думаю, NS это серьёзная необходимость - во многих продвинутых языках(с точки зрения реализации возможностей ООП) Namespace'ы уже давно реализованы, так что PHP, пусть и слегка запоздало, просто подтягивается до неписаных стандартов. имхо.
      • Сам писал только на 4 пхп, поэтому не видел раньше в пхп оператора use =)
Только авторизованные пользователи могут оставлять комментарии. Авторизуйтесь, пожалуйста.