Изолированные окружения в JPHP
После статьи про скрытые возможности DevelNext, многим стал интересен специальный класс Environment, который позволяет создавать изолированные или частично изолированные окружения для выполнения кода. Раз эта тема интересна многим, тогда мы расскажем, как они работают изнутри и рассмотрим работу с окружениями более детально.
Класс EnvironmentА если быть более конкретным, то имя класса
Что же такое окружение? В DevelNext и JPHP любой код обязательно выполняется в каком-то окружении, даже если это и не заметно. Окружение содержит множество информации, это в первую очередь – глобальные переменные, загруженные модули, классы, константы и функции, даже статические переменные классов, у каждого окружения свой буфер вывода (см. функции ob_*). К тому же, окружения имеют свои опции.
Для чего это нужно?Когда создавался JPHP, мы естественно брали в расчет оригинальный движок Zend PHP. Оригинальный движок умеет работать в изолированных разных окружениях, только это обеспечивает обычно веб-сервер, например Apache Server. В самом же языке нет возможностей создавать свои окружения, только через дополнительные расширения.
И если кто-то захочет написать веб-сервер на JPHP, он легко сможет повторить полную изолированность скриптов на каждый запрос, как это есть в Zend PHP и Apache Server, применяя заветный класс Environment. Если еще подумать, то этот класс можно применять, если вы ходите добавить в свою программу систему скриптов, чтобы пользователи вашей программы могли с помощью скриптов php расширять ее функционал. Изолированность окружений поможет оградить доступ к основному функционалу вашей программы из этих скриптов.
Начинаем работуСоздание окружения это простой процесс, нам всего-то нужно создать объект:
После чего, мы легко можем выполнять код от “имени” этого окружения, т.е. в его рамках:
Чтобы передать в окружение переменную извне, используются стандартные возможности языка php, через use:
Импорт классов, функций, константЕсли вы просто создадите окружение, как описано выше, то никакие ваши объявленные классы и функции в этом окружении работать не будут. При попытке их использовать будут возникать ошибки по типу Class ‘…’ not found и т.п. Также не будут работать автозагрузчики классов (autoloaders), т.е. автоматически классы подключаться не будут в ваше окружение. JPHP по-умолчанию настраивает автозагрузку классов для первого окружения, в котором выполняется ваш код. Но это всё не беда и легко настраивается.
Для начала, попробуем включить автозагрузку классов как в окружении извне, в котором было создано наше окружение:
А теперь, попробуем импортировать наш написанный класс в окружение:
Импорт функций происходит по тому же принципу, только не забывайте, что указывать надо полное имя функции или класса, вместе с их namespace:
Для того, чтобы в окружении объявить константу, используем специальный метод
Переопределяем вывод echoУ вас также есть возможность повесить хук на вывод текста через функции echo, print, print_r, var_dump и т.п. Иногда это удобно и сделать это также просто:
Механизм обмена сообщениямиУ класса Environment также есть два метода для реализации функционала обмена сообщениями, по типу RPC.
Экспорт классов и функцийЕсли внутри окружения объявлена функция или класс, которых нет в родительском окружении, то их можно в него экспортировать с помощью методов exportClass() и exportFunction(). Методы работают так же как и importClass() + importFunction(), только в обратную сторону.
Копируем окружениеЕсли вы хотите создать окружение точно такое же как и родительское, со всеми глобальными переменными, функциями, классами и т.п., то и для этого есть возможность:
Однако, не забывайте, что создается копия окружения, а не ссылка одного на другое, поэтому, если в одном вы объявите новый класс уже после создания окружения, то в другом он автоматически не появится. Вы по прежнему можете использовать методы для импорта и экспорта классов и функций.
Окружения для потоковПо-умолчанию, окружения не пригодны для работы с потоками, так код в них быстрее работает. Окружения по-умолчанию будут выдавать всякие непонятные ошибки при работе с потоками, это нормально, т.к. они не предназначены для этого. Однако, есть возможность включить поддержку потоков для создаваемого окружения через опцию:
Одноразовые окруженияТакие окружения необходимы, чтобы код в них один раз выполнился, а далее их использовать – нет надобности. Все это сделано наподобие того, что описано в начале статьи, по тому же принципу, как работает оригинальный Zend PHP. Чтобы создать такое окружение, используйте специальную опцию HOT_RELOAD:
Эта опция позволит грузить все модули, классы и т.п. с чистого листа, реализуя таким образом горячую перезагрузку кода. Окружения с данной опцией пока являются экспериментальной возможностью, они могут накапливать память, не освобождая её, что может приводить к ошибкам в программе. Это может происходить не часто, используйте данную возможность только во время разработки программы или с осторожностью.
Заключение.Есть еще некоторые специфичные возможности окружений, например source map-ы и пакеты, о которых мы возможно когда-нибудь расскажем в следующих статьях. Эти темы слишком обширные и специфичные для данной статьи.