D7: Объект сервера, работаем правильно с переменными сервера

  • D7: Объект сервера, работаем правильно с переменными сервера

    Антон Долганин 21 Января 2015 8:56 13493
    В новом ядре Битрикс D7, чтобы достучаться до некоторых серверных переменных, нужно использовать специальный класс. Я про такие переменные сервера как IP-адрес, хост, и так далее. Коротенечко пробежимся по классу.

    Итак, вызывается переменная так:
    $context = \Bitrix\Main\Application::getInstance()->getContext();
    $server = $context->getServer();

    Вот теперь мы можем обращаться к переменным. Перечислю методы, доступные на данный момент:

    $server->getDocumentRoot() - док.рут текущий.
    $server->getPersonalRoot() - путь Битрикс, по умолчанию равен /bitrix.
    $server->getHttpHost() - HTTP_HOST
    $server->getServerName() - SERVER_NAME
    $server->getServerAddr() - SERVER_ADDR
    $server->getServerPort() - SERVER_PORT
    $server->getRequestUri() - REQUEST_URI
    $server->getRequestMethod() - REQUEST_METHOD
    $server->getPhpSelf() - PHP_SELF
    $server->getScriptName() - SCRIPT_NAME

    Если методов не хватает, можно получить любую переменную $_SERVER таким образом:
    $server->get('HTTP_X_REAL_IP');

    И есть еще два метода, применение которых на практике я пока не знаю:
       public function rewriteUri($url, $queryString, $redirectStatus = null)
       {
          $this->values["REQUEST_URI"] = $url;
          $this->values["QUERY_STRING"] = $queryString;
          if ($redirectStatus != null)
             $this->values["REDIRECT_STATUS"] = $redirectStatus;
       }
    
       public function transferUri($url, $queryString = "")
       {
          $this->values["REAL_FILE_PATH"] = $url;
          if ($queryString != "")
          {
             if (!isset($this->values["QUERY_STRING"]))
                $this->values["QUERY_STRING"] = "";
             if (isset($this->values["QUERY_STRING"]) && ($this->values["QUERY_STRING"] != ""))
                $this->values["QUERY_STRING"] .= "&";
             $this->values["QUERY_STRING"] .= $queryString;
          }
       }



    .
Олег
21 Января 2015 10:13
Антон, вам правда удобнее писать
$context = \Bitrix\Main\Application::getInstance()->getContext();
$server = $context->getServer(); 
$server->getDocumentRoot()

чем
$_SERVER["DOCUMENT_ROOT"]

???

Какой смысл??
Антон Долганин
21 Января 2015 10:21
Олег, это принцип ООП - не лезть в глобальные переменные.  (один из минусов ООП кстати это как раз местами излишество кода)

Естественно использование не предполагает перед каждым вызовом нужного метода ставить getInstance и так далее. Определите $context в начале файла и все (или в методе своего класса).  
Антон Долганин
21 Января 2015 10:22
Естественно использование не предполагает перед каждым вызовом нужного метода ставить getInstance и так далее.
\Bitrix\Main\Application::getInstance() - довольно основная штука, изнутри которой можно и get и post доставать, и серверные переменные. Это ООП-шное подобие старого доброго $APPLICATION, который надо уже забывать помаленьку.  
Олег
21 Января 2015 10:28
Это ООП-шное подобие старого доброго $APPLICATION, который надо уже забывать помаленьку
Зачем забывать удобные вещи? В чем выигрыш?

Возможно я не прав, но с моей колокольни это выглядит "как сделать всё сложнее, а код более громоздким" - индусский подход по раздуванию кода.
Антон Долганин
21 Января 2015 10:52
Олег, к сожалению, я не готов полноценно ответить на такие вопросы. Так просто правильно, минимизирует ошибки, позволяет в будущем работать с кодом новым специалистам (текущая "школа" уже попросту не выпускает тех, кто знал как писать под PHP4). Ну и так далее.

Ну и такая программа, с глобальными, больше уязвима к ошибкам человека (а где ошибка человека, там может быть и ошибка безопасности).
Что будет, если в header.php вставить такой код в конце?
<?unset($APPLICATION)?>
А все, что ниже - умрет. Теперь попробуйте сломать сайт, если мы используем Bitrix\Main\Application::getInstance().

Да, пример надуман, но он показывает, что в случае когда все всё пишут правильно, никто не сможет навредить другим (только себе). Это примерно как новый D7-фильтр. Раньше ошибка в фильтре могла привести к печальным последствиям, сейчас просто выплюнется екзепшен именно тому разработчику, кто такой код пишет.

Все равно неубедительно? :) Ну вот пример с сабжем: http://bxapi.ru/code/C7dxMCH6517OKHa/
Олег
21 Января 2015 11:08
Спасибо, что уделили время!

Да, вполне убедительно. Для командной разработки самое то, наверное.
Когда делаешь один и хотя бы примерно помнишь, где и что писал, шанс таких ошибок минимален.

Правда, так нормальной документации по D7 не попадалось, в основном небольшие заметки от вас и других разработчиков, а вот документации - не, не видел.

Когда-то делал большой каталог на highload (под миллион товаров) с использованием D7 - обплевался, сколько "лишнего" надо писать, что бы сделать чуть-чуть. На этот D7 еще свою обертку писать надо, что б удобно было :D
Никита Самохвалов
21 Января 2015 11:58
Никогда не знаешь, что с проектом будет дальше. Может через неделю к вам подключатся ещё разработчики, может через год им вообще будут заниматься другие люди.

ООПшный подход, кроме прочего, даёт гарантию того, что вы будете правильно работать с данными. Вы просто говорите синглтон-классу, что ему нужно сделать, а вся магия происходит под капотом. Во-первых, вы не забудете произвести важные операции (если они нужны, скорее всего, они уже будут записаны в классе), во-вторых у вас будет поддержка обновлений. Появилась необходимость производить доп. операции при записи какой-либо переменной — правим только метод set() класса.
В плане документации выступлю в защиту Д7. Все методы и классы в новом ядре документируются, а названия им даются «человеческие». Поэтому, просто начинайте в своей ИДЕ писать название сущности, с которой хотите работать, и смотрите результаты автокомплита.
Алексей
21 Января 2015 13:43
Зачем забывать удобные вещи? В чем выигрыш?
Тестирование и глобальные переменные - несовместимые вещи, например.
Константин Лех
21 Января 2015 11:15
Когда делаешь один и хотя бы примерно помнишь, где и что писал, шанс таких ошибок минимален.
Это только первые пару недель ;)
Сергей
21 Января 2015 11:30
Антон, а не в курсе как обходить ситуацию с $APPLICATION->AuthForm()? Может в курсе когда битрикс планирует отойти от глобальных переменных?
Алексей
21 Января 2015 13:52
Битрикс планирует. Потому как глобальные переменные - зло.

Отвечая сразу всем интересовавшимся скажу, что для больших проектов, а так же для проектов, в которые вовлечены более пары человек, нет особых альтернатив ООП подходу. Да, код становится объемнее. Потому что нет панацеи. За все надо платить. Но код становится более устойчивым и управляемым. Ведь данные скрываются областью видимости, предоставляя наружу только методы для управления. Появляется возможность динамически подменять поведение. Существенно упрощается дальнейшее развитие кода. Ну и т.п.

Стоит заметить также, что на текущих версиях php целесообразно применять комбинированный подход. Т.е. там, где достаточно массивов, делать объекты может оказаться не целесообразно по вопросам производительности.
Антон Долганин
22 Января 2015 6:03
Пока с этим еще пожить придется, к сожалению :) но вообще интересно было бы на предстоящей партнерке планы обсудить хотя бы.
Алексей
22 Января 2015 8:55
Антон (Scrooge)
23 Января 2015 6:11
Ребят, PHPStorm до 5 Февраля со скидкой 40% для девелоперов, цена прошлого года, может кому пригодится :)
Сергей
26 Января 2015 10:15
Блин, я в начале января тока продлил себе за конский ценник(((
Антон (Scrooge)
26 Января 2015 22:25
Да, жалко)  Но Вы не жалейте, это инструмент приносит нам уйму дохода, миллионы фунтов стерлингов.;)
А я целый год ждал скидку, как-то чисто случайно у меня винда заглючила, я ее переустановил, зашел скачать новый PhpStorm, на тебе, получите распишитесь:)
ivanpanfilov
2 Февраля 2015 10:31
Типичный оверинженеринг бред.
Расмус не для этого создавал PHP.
фильософия PHP - это быстрый доступ к основным переменным веб окружения, разбиение приложения на независимые скрипты (микросервисы), встроенный набор функций выполняющий типовые задачи.

то что сейчас пытаются реализовать в Bitrix - программировать с такими подходами можно было делать еще лет 10 на java.
Антон Долганин
3 Февраля 2015 4:23
Я вам предупреждение выношу (потом бан). Мне троллей и негатива хватает на других сайтах. В своем блоге не потерплю. Есть что по делу - всегда пожалуйста. Нет - не задерживайтесь и проходите мимо.
Алексей
10 Мая 2015 23:54
Извиняюсь, что комментирую старый пост, но не мог мимо пройти.
Это, вроде как

$context = \Bitrix\Main\Application::getInstance()->getContext(); 


проще заменить этим:

use \Bitrix\Main\Application;


Ну и далее просто

$context = Application::getInstance()->getContext(); 
.
Антон Долганин
11 Мая 2015 4:23
Согласен :) спасибо.
Сергей
25 Июня 2015 10:30
Пожалуй добавлю выдержку из общения с ТП Битрикса, может кто-то так же столкнется с этим.

Поблема - путь откуда вызывается приложение не соответствует пути которые подставляется в include, в одном случае home/bitrix/www/ в другом work/bx/www.

Ответ1: Скорее всего проблема в символической ссылке на корневую папку сайта, мы это тоже тестируем.

Ответ2: В данной ситуации мы можем посоветовать только одно, с учётом того, что сейчас ядро продукта не работает по большей части с D7 (код которого Вы используете), также пока не использовать эти экспериментальные классы.

Так что будьте осторожны с использованием данного метода, если у вас идут символические ссылки на папки.
Антон Долганин
26 Июня 2015 5:33
Сергей, спасибо за комментарий.