Первичная обработка внешних данных, небесные врата

SKY / WINGS / FIRST /
SKYGATE1
В одной из последних версий Laravel, в папке `Illuminate/Routing` содержится около 140 килобайт кода в большой куче файлов, это в полтора раза больше чем весь код coresky. Это еще без учета файлов Symfony, которые тоже используются. В своих комментариях на хабре, я упоминал, что веб-роутинг или маршрутизация, это не очень хорошая идея. А где хорошая спросите вы? Все просто: первых два параметра адреса запроса, определяют соответственно конкретный контроллер и действие в нем (метод контроллера). Но здесь чего-то не хватает... да, небесных врат!

Общая форма и типы URI



1) указатель языка и/или мобильной версииприсутствуют при необходимости
2) субдоменто-же самое
3) доменимеется всегда, главная часть общего адреса запроса
4) путь к проектуконстанта PATH на продакшн обычно имеет значение "/", т.е. эта часть урл не используется. Но на DEV удобно помещать проекты в под-папки одного виртуального сервера, поэтому PATH обычно содержит имя проекта и папку www, ту которая подразумевается корнем виртуального сервера на продакшн
5) семантическая часть URI$sky->surl, если не FALSE, то содержит части семантического урл и именно его первые две части определяют контроллер и действие. В папке `www`, на картинке выше, находится файл-обработчик всех запросов index.php и файл .htaccess, в котором правила `mod_rewrite` способствуют преобразованию части 5 в значения массива $sky->surl
6) строка запросаQuery String, все что после знака вопроса, заполняют массив $_GET в ядре PHP. При использовании семантических урл, может отсутствовать

Все URI, обрабатываемые кодом coresky, целесообразно разделить на три типа:

1. Содержащие семантическую часть, но только один параметр, когда символ папки "/" не используется, например: https://example.net/pagename?query=string. Такие урл, считаются основными, они не имеют проблем, присущих семантическим со знаком "/" и в то-же время являются семантическими.

2. Не содержащие семантическую часть, например: https://example.net/?query=string или, почти то же самое: https://example.net/index.php?query=string

3. Семантические урл, содержащие знак "/", предпочтительны для индексации поисковыми машинами: https://example.net/page/action/somethingelse?query=string, но имеют проблему.

Если в SKY-приложении используются только URI первого или второго типа, то везде можно использовать относительную адресацию, например у вас в шаблоне может использоваться запрос картинки:
<img src="img/apple.jpg"/>, эта запись наиболее короткая и производительная. Не будет проблем ни на DEV, когда проект установлен в под-папку виртуального сервера и используется PATH-часть, ни на продакшн инсталляции приложения. При использовании семантических URI, необходимо указать PATH-часть в адресе картинки, которая может быть разной на DEV и на продакшн: <img src="<?php echo PATH ?>img/apple.jpg"/> или используя оператор парсера шаблонов Jet: <img src=@p(img/apple.jpg)/>. Но если SKY-приложение важно для вас, и вам не лень настроить отдельный веб-сервер для его DEV инсталляции, можно предварять адреса корнем виртуального сервера: <img src="/img/apple.jpg"/>, такой подход также более производительный, но код приложения будет не работоспособным при инсталляции приложения в под-папку виртуального сервера.

Так как CSN-AJAX URI генерируются автоматически и никогда нет необходимости в их индексации поисковыми роботами, то для них всегда удобно использовать URI второго типа. Для веб-приложений, которые не должны индексироваться (CRM работающие в локальной сети), удобно для всех остальных ссылок, использовать URI только первого типа, но не третьего, ввиду описанной выше проблемы. Для публичных же сайтов, для ссылок, которые желательно проиндексировать поисковыми машинами, можно использовать полные семантические URI.

Вычисление частей URI:

001
002
003
004
005
006
<?php
 
define('PATH'preg_replace("|[^/]*$|"''$_SERVER['SCRIPT_NAME']));
define('URI', (string)substr($_SERVER['REQUEST_URI'], strlen(PATH)));
count($this->surl explode('/'explode('?'URI)[0])) > or $this->surl false;
 


Если происходит CSN-AJAX запрос, то заранее известно, что он будет идти по схеме:

https://example.net/index.php?AJAX=controller&controller=action...

т.е. если используется контроллер с_controller и действие j_action, то всю эту часть URI можно обработать на этапе компиляции кода врат! В генерированном же коде SkyGate, будут проверяться только дополнительные параметры адресной части запроса, если они есть. Для с_controller::default_j() статическая часть будет:

https://example.net/index.php?AJAX=controller&controller=...

Я не анализировал код маршрутизации Laravel, но даже если он компилируется в исполняемые файлы, подобно коду SkyGate, использует прямые файлы для фиксированной части запросов, использование визуальной утилиты более эффективно. Программисту не нужно писать код маршрутизации, вместо этого, просто выбрать среди доступных опций необходимые ограничения и фильтрации, пред-установки для файлов sitemap, канонических URL и прочего хорошо формализирующегося функционала. Или маршрутизаторы Laravel так и бегают по длинной цепочке регулярных выражений, для детектирования нужного Route при боевых кликах?

Визуальное программирование


Кто вам сказал что "Full stack framework" типа Symfony это хорошо? Если вы хотите потренировать свой мозг в понимании и связывании кучи абстракций, то да, это неплохо. Проснитесь, вы что забыли какую цель преследует отрасль программирования? Нужно просто, "допилить" железки, чтобы они работали как надо. Конечная цель программирования, - сделать компьютер своим хорошим другом, который понимает вас вербально с полу слова, когда написание текстов программ человеком уйдет в небытие. Мы должны стараться формализовать процесс программирования, тогда достичь цели программирования будет намного проще. Если ясно, что визуальное программирование решает на 100% задачу, мы должны использовать его, так как оно всегда проще. Формализовав все программирование, мы сможем программировать полностью визуально и в конечном итоге вербально.

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

SkyGate


Разделяй и властвуй. Для врат хорошо работает старая истина. Активные методы контроллеров sky-приложений, т.е. методы с префиксом a_, j_, а также empty_a(), empty_j(), default_a(), default_j(), выглядят для программиста просто, код врат в них не включается. Но для реальных запусков будет использован компилированный код контроллеров, включающий код GATE. Код небесных врат хорошо формализуется, и для него удобно использовать визуальное программирование, чтобы определить ограничения для каждого метода контроллера. После того как вы определили код в новом активном методе контроллера (action), необходимо, как минимум, указать в визуальной утилите GATE, допустимые HTTP методы для данного action и дать список валидных входных переменных, иначе контроллер выдаст 404 ошибку. Исключение составляет главная страница сайта, для нее, по умолчанию, будет включен метод GET и будет указано отсутствие дополнительных входных данных. Визуальная утилита, сохраняет конфигурацию GATE в хеш-массиве, в файле main/app/gate.php, а компилятор файлов контроллеров, подобно компилятору шаблонов Jet, использует эту информацию и дополняет код контроллеров генерированным кодом GATE. Компилированные контроллеры, будут использоваться для реальных запусков, компилируются только лишь один раз, как и шаблоны Jet и помещаются в папку var/gate. Пример хеш массива GATE:

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
<?php
 
$skygate = [
  'c_main' => [
    'empty_a' => //..,
    0 => // all action's in c_main
  ],
  'c_node' => [
    'empty_a' => //...
    'a_show' => //...,
    'j_edit' => //...,
    'j_delete' => //...,
    0 => // all action's in c_node
  ],
//....
  0 => [
    // all controller's scope
  ],
];
 

Рефлексивный код SkyGate, проверяет валидность входных данных (типы HTTP запросов, адресная часть, postfields часть и способ её кодирования, редко body часть), фильтрует входные данные, делает замену контроллеров и/или действий в них, подготавливает входные данные к передаче в контроллеры, в общем все что может потребоваться на этом этапе.

Я совершенно удивлен, почему в PHP до сих пор нет нормального функционала для работы с разделяемой памятью? Только лишь для версии PHP 7.2 появилось нечто подобное, то что чрезвычайно необходимо для реализации правильной архитектуры любого сайта в Интернете, смотрите http://php.net/manual/ru/class.pht-hashtable.php. Функционал shmop_XXX редко компилируется по умолчанию, не соответствует реальным требованием и похож на игрушку для новорожденных.

Представьте: каждый клик на сайте загружает системную конфигурацию веб-приложений в память и только лишь потом ее использует. Но зачем это делать постоянно для каждого клика? Вначале своей эволюции PHP пытался вкладывать архитектуру веб-приложений непосредственно в сам язык. Иногда это было неуклюже, вспомните функцию magic_quotes_gpc(), но иногда совершенно правильно. Я считаю это делать нужно! Именно это качество PHP сделало язык таким популярным, каким он есть сейчас. Но в последнее время, разработчики PHP, похоже отказались от пути включающего явную ориентацию языка на применение в веб. Имхо, напрасно. Ориентировать архитектуру языка на использование в веб, было бы правильно, но нужно это делать с умом.

Представьте, ваше приложение загрузило некоторую системную конфигурацию веб-сайта в хеш-массив, только лишь один раз, а все остальные клики читают информацию сразу, прямо из shared memory! Так должно быть, это естественно. Достаточно, чтобы эта память была доступна только лишь для чтения:

001
002
003
004
005
006
007
<?php
 
if (!isset($%sys_conf))
    create_shared_array($%sys_confSystem::loadConfiguration());
// $%sys_conf - используйте хеш-массив конфигурации из разделяемой памяти свободно, как обычный
// массив, но только для чтений
 


Метод Gate::parse()


001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
<?php
class Gate
{
//..
    function parse($fn$ary = []) {
        $c $f $depth $found 0;
        $list = [];
        $class basename($fn'.php');
        $tpl_class explode(' ''T_OPEN_TAG T_CLASS T_STRING T_EXTENDS T_STRING {');
        foreach (token_get_all(file_get_contents($fn)) as $v) {
            if (is_array($v)) {
                if (in_array($v[0], [T_WHITESPACET_COMMENTT_DOC_COMMENT])) {
                    2 == $f or $this->out .= $v[1];
                    continue;
                }
                if (T_CURLY_OPEN == $v[0] || T_DOLLAR_OPEN_CURLY_BRACES == $v[0])
                    $depth++;
                if (!= $c) {
                    if ($v[0] != constant($tpl_class[$c++]) || == $c && 'Controller' != $v[1]) {
                        $c 0;
                    } elseif (== $c) {
                        $v[1] == $class and $found or $c 0;
                    }
                } elseif (== $f) {
                    if (T_STRING == $v[0] && (in_array($v[1], $this->sf)
                           || in_array(substr($v[1], 02), ['a_''j_']))) {
                        $f++;
                        $func = [$v[1], ''];
                    } else {
                        $f 0;
                    }
                } elseif (!$f && T_FUNCTION == $v[0]) {
                    $f 1;
                } elseif (== $f) {
                    $func[1] .= $v[1];
                }
                if (!= $f)
                    $this->out .= $v[1];
                continue;
            }
            if ('{' == $v) {
                if (!$depth++ && == $c)
                    $c 7# in class
                if (== $depth && == $f) {
                    $list[$func[0]] = $func[1];
                    if ($ary) {
                        $com = isset($ary[$func[0]][0]) ? $ary[$func[0]] : [0];
                        $this->out .= $func[0] . '($sky, $user) {' $this->code($com$func[1]);
                    }
                    $f 0;
                    continue;
                }
            } elseif ('}' == $v) {
                !--$depth and $c 0# out of class
                1 == $depth and $f 0# out of func
            } elseif (== $f) {
                $func[1] .= $v;
            }
            if (!= $f)
                $this->out .= $v;
        }
        $this->+= count($list);
        return $found $list : [];
    }//..
 


Параметры активных методов контроллеров


Все внешние данные поступают в контроллеры, для обработки, в параметрах функций (методов). Активные методы контроллеров могут содержать строго 0, 1,2 или 3 параметра:

нет параметров - адресная и post часть внешних данных не определена. Проверяется, что никакие данные post не передаются вообще, как и дополнительные данные адресной части (кроме тех что определили контроллер и action). Параметры не могут отсутствовать в методах default_a() или default_j(), должен быть как минимум один параметр для адресной части.

1 параметр - определена только адресная или только post часть. Если определение в адресной части всего одно, а post-часть не определена, для него не нужно использовать ALIAS. Даже если ALIAS определен, он не используется, так как входное значение передается прямо в параметр. Если определений более одного, данные передаются как объект, но если выставлен флаг ADDRESS_AS_ARRAY, то как массив. В случае, если определение не имеет статического ключа, для каждого параметра нужно определить ALIAS, используя "as" например: 0 => %news(\d+)% as id. Статический ключ может присутствовать в "Query String" части (после знака вопроса) или в post данных. Если ключ массива определения не INT, но STRING, то эта строка и есть статический ключ, например: id => %news(\d+)%. Во втором примере определения, используется ALIAS: 0 => %news(\d+)% as id. ALIAS необходимы для расшифровки семантической части URL или когда ключи "Query String" (также и urlencoded postfields) не статичны. В последнем случае, ключ-значение вносят 2 параметра входных данных вместо одного.

2 параметра - может быть определена адресная и post часть. Если определены обе части, то первый параметр относится обязательно к адресной части, а второй к post-части. Используются непосредственные значения, объекты или массивы аналогично как и описано выше. Для post-части имеется для выставления флаг POST_AS_ARRAY.

Если определена только адресная часть или только post часть, то первый параметр выдает значение обязательно непосредственно, а второй может непосредственно (если определений всего 2) или объект или массив, если их больше.

3 параметра - аналогично как и в предыдущем пункте. Когда определены и адресная часть и post часть, то первый параметр обязательно касается адресной части, а третий обязательно post части. Второй же параметр метода контроллера может относиться или к GET или POST и зависит от общего количества определенных параметров и присвоенных им или не присвоенных ALIAS. Например, если адресная часть имеет 5 определений и первое определение есть регулярное выражение без присвоенного ALIAS, то первый параметр, это параметр адресной части и передается напрямую. Второй параметр это массив или объект, содержит остальные 4 параметра адресной части.

Конвенция о соглашении именования параметров: если параметр передается напрямую, его нужно именовать в соответствии с логикой, которую он несет, например $id. Если параметры передаются в массиве или объекте, имена должны быть: $get, $post, $put, в соответствии с применяющимся HTTP методом. Если используется, например HTTP метод PUT, все вышеописанное относится к PUT так же как и для POST. Адресная же часть присутствует всегда, не только когда используется HTTP метод GET, но и совместно со всеми остальными HTTP методами.
published ENERGY - 12 Nov 2018 18:24 GMT
last edit - 29 Nov 2018 11:35 GMT
 +  0  -  add comment