Выкладываю кусочек тематики, над чем сейчас и работаю. Возможно вам будет это интересно, а так показать возможность данной реализации. Для примера, взял пару строк пхп кода по которому постараюсь объяснить, как это все работает. PHP: $container -> get( \Commands :: class ) -> typeChat( $container -> get( \Commands :: class ) -> getParseTags()['type'], static function ( Container $container ): void { $container -> get( \Commands :: class ) -> randomMessageSend( 'offline' ); } ); $container -> get( \Commands :: class ) -> typeChat( 'Normal' ); $container -> get( \Commands :: class ) -> arr -> one -> {2} -> three; Теперь попробуйте каждый элемент аргументировать в виде json строки. Да, будет начало что-то вроде {"var":{"name":"container","result":{......}}} - но это будет слишком низкоуровневый контент. Что у меня вышло с многоразовыми переделками: Спойлер: json PHP: [ { "method":[ {"container":"Commands"}, "typeChat", [ { "get_results_for_keys":[ { "method":[ { "container":"Commands" }, "getParseTags" ] }, ["type"] ] }, { "callable":{ "method":[ { "container":"Commands" }, "randomMessageSend", ["offline"] ] } } ] ] }, { "method":[ { "container":"Commands" }, "typeChat", ["Normal"] ] }, { "get_results_for_keys":[ {"container":"Commands"}, ["arr","one",2,"three"] ] } ] Т.е. каждый пак/строк кода, представлен в такой архитектуре: PHP: [ { 1 пак }, { 2 пак }, { 3 пак } ] Актуально рабочая/тестовая версия http://sandbox.onlinephpfunctions.com/code/bdc5e6b8c1a2d743473b0588ae94bed66f2ac882 Спойлер: Пояснение По выше перечисленной ссылке с 69 строки, представлен анонимный класс, который собирает так называемую Паутину "callable мап схему" и после дергает, в нужном местоположении, свой пакет завернутого кода. Структура самого класса без пользовательских fun_<name> методов: PHP: new class ( ...$args ) { private $container; # здесь составляется вся схема с вложенными Closure функциями и его аргументов, все. # вложения во вложенном protected $passage = []; # тестовая переменная для удобного просмотра содержимого и в дальнейшем правка архитектуры. public $passage_test = []; # Сохраняем в переменную декодированный массив, входящего json списка protected $constructor; # Регистрируем имена для пользовательских методов fun_<name>() protected $register_fun = [ 'container', 'method', 'get_results_for_keys', 'callable', ]; public function __construct ( Container $container ) { $this -> container = $container; } /* - импортируем и проверяем json перед использованием */ public function import( string $string ): bool { $this -> constructor = json_decode ( $string, true ) ?: []; return json_last_error () === JSON_ERROR_NONE; } /* - Собираем мап схему без запуска и выводим. */ public function handle() { $this -> passage( $this -> constructor ); return $this -> passage; } /* - Рекурсивное прохождение */ protected function passage( array $a ) { $passage = &$this -> passage; $this -> passage = &$passage[]; $passage_test = &$this -> passage_test; // тест $this -> passage_test = &$passage_test[]; // тест # пример: # {"container":"Commands"} foreach ( $a AS $key => $iteration ) { # Сверяем ключ со списком регистрации имен - container - yes if ( in_array ( $key, $this -> register_fun, true ) ) { $this -> {'fun_' . $key}(); //$this -> passage( $iteration ); } # Commands - set arguments if ( is_string ( $iteration ) || is_numeric ( $iteration ) ) { $this -> passage[] = static function ( Container $container ) use ( $iteration ): string { return $iteration; }; $this -> passage_test[] = $iteration; // тест } else #{"name...":[{"container":"Commands"}]} { $this -> passage( $iteration ); # [{"container":"Commands"}] } } $this -> passage = &$passage; $this -> passage_test = &$passage_test; // test } /* по запуску схемы, содержимое метода рекурсивно ищет и запускает аргументы callable or пакеты кода key *main { *main ( get_map ), 0_arguments - { *main ( get_map ), 0_arguments - { *main ( get_map ), 0_arguments - { closure - values, closure - values, closure - values } } } } */ protected function get_map(): callable { return static function ( Container $container, callable $map, $passage ) { if ( is_callable ( $passage ) ) { return $passage( $container ); } elseif ( isset ( $passage['*main'] ) ) { return $passage['*main']( $container ); } $a = []; foreach ( $passage AS $p ) { $a[] = $map( $container, $map, $p ); } return $a; }; } }; Пользовательский метод в классе (в качестве шаблона) выглядит так: PHP: protected function fun_<name>() { $passage = &$this -> passage; $passage_test = &$this -> passage_test; // test $passage_test['main'] = 'fun_<name>'; // test $map = $this -> get_map(); $passage['*main'] = static function ( Container $container ) use ( &$passage, $map ) { var_dump('<name>'); // тест # тело пхп кода return ...; }; } Спойлер: json По json`у - разработав некие правила, допустим: Чтоб собрать обычный метод, нужно следовать по такому шаблону PHP: { "method":[ {<this>}, <name>, [<arguments>] or [] ] } его реализация: PHP: protected function fun_method() { $passage = &$this -> passage; $passage_test = &$this -> passage_test; $passage_test['main'] = 'fun_method'; $map = $this -> get_map(); $passage['*main'] = static function ( Container $container ) use ( &$passage, $map ) { var_dump('method'); $_this = $map( $container, $map, $passage[0][0] ); $_name = $map( $container, $map, $passage[0][1] ); $args = ( isset ( $passage[0][2] ) ? $map( $container, $map, $passage[0][2] ) : [] ); //var_dump ( $_name, $args ); return $_this -> {$_name}( ...$args ); }; } Спойлер: Сборка Для всего творения, мне нужно было задействовать сторонние классы, для действительного факта об работоспособности конструктора. Поэтому по ссылке (выше) присутствует лишний код. Контейнер PHP: final class Container { private $container = []; public function set( string $name, callable $func ): void { if ( isset ( $this -> container[$name] ) ) { throw new \Error( $name . ' already exists!' ); } $this -> container[$name] = $func; } public function get( string $name ) { if ( ! isset ( $this -> container[$name] ) ) { return null; } if ( $this -> container[$name] instanceof \Closure ) { return $this -> container[$name] = $this -> container[$name]( $this ); } return $this -> container[$name]; } } Произвольный класс с методами PHP: class Commands { public function __construct ( Container $container ) { $this -> container = $container; $this -> arr = json_decode ( '{"one":{"2":{"three":111}}}' ); } public function typeChat( $a, $b = null ) { var_dump ( "typeChat -- {$a}" ); if ( $b ) { var_dump ( $b( $this -> container ) ); } } public function getParseTags() { return ['type'=>666]; } public function randomMessageSend( string $string ) { return "randomMessageSend -- {$string}"; } } Спойлер: Запуск PHP: $c = new Container; $c -> set( \Commands :: class, static function ( Container $container ) { return new Commands( $container ); } ); $b = $a( $c ); /* new main обворачивать в {} */ $str = ' [ { "method":[ { "container":"Commands" }, "randomMessageSend", [ { "get_results_for_keys":[ { "method":[ { "container":"Commands" }, "getParseTags" ] }, ["type"] ] } ] ] } ]'; if ( $b -> import( $str ) ) { $res = $b -> handle(); //print_r ( $b -> passage_test ); foreach ( $res AS $_2 ) { foreach ( $_2 AS $_3 ) { print_r ($_3['*main']($c)); } } } else { echo 'Не корректный json'; } Да, запуск схемы простенький (два foreach), т.к. полноценно еще не создано ни-че-го. Про $b -> passage_test верху описывал, что выводит. Спойлер: Результат Результат будет ввиде Debugs PHP: string(6) "method" string(9) "container" string(20) "get_results_for_keys" string(6) "method" string(9) "container" randomMessageSend -- 666 $b -> passage_test PHP: Array( [0] => Array( [0] => Array( [main] => fun_method [0] => Array( [0] => Array( [main] => fun_container [0] => Commands ) [1] => randomMessageSend [2] => Array( [0] => Array( [main] => fun_get_results_for_keys [0] => Array( [0] => Array( [main] => fun_method [0] => Array( [0] => Array( [main] => fun_container [0] => Commands ) [1] => getParseTags ) ) [1] => Array ( [0] => type ) ) ) ) ) ) ) ) Спойлер: Для чего это все ? Пишу для нейросети API "команды" и развитие.
PHP: $commands = $container -> get( \Commands :: class ); [ 'type' => $type, 'name' => $name, 'message' => $message ] = $commands -> getParseTags(); $commands -> reloadDaemon( static function ( Container $container ) use ( $type, $name ): void { $container -> get( \Commands :: class ) -> setParseTag( 'name', $name ); $container -> get( \Commands :: class ) -> typeChat( $type, static function ( Container $container ): void { $container -> get( \Commands :: class ) -> write2chat( 'Команда принята' ); } ); } ); $systems = $container -> get( \Systems :: class ); $values = $commands -> getValues(); $time = strtotime ( "+{$values[1]} seconds" ); PHP: [ {"copy":["Commands",{"container":"Commands"}]}, {"copy":["Systems",{"container":"Systems"}]}, { "copy":[ "history_tags", { "method":[ {"paste":"Commands"}, "getParseTags" ] } ] }, { "method":[ {"paste":"Commands"}, "reloadDaemon", [ { "callable":[ { "method":[ {"paste":"Commands"}, "setParseTag", [ "name", { "get_results_for_keys":[ {"paste":"history_tags"}, ["name"] ] } ] ] }, { "method":[ {"paste":"Commands"}, "typeChat", [ { "get_results_for_keys":[ {"paste":"history_tags"}, ["type"] ] }, { "callable":{ "method":[ {"paste":"Commands"}, "write2chat", ["Команда принята"] ] } } ] ] } ] } ] ] }, {"copy":["getValues",{ "method":[ {"paste":"Commands"}, "getValues" ] }]}, {"copy":["time",{ "function":[ "strtotime", [ { "function":[ "sprintf", [ "+%s seconds", { "get_results_for_keys":[ {"paste":"getValues"}, [1] ] } ] ] } ] ] }]} ]
PHP: /* - {"logical_operators":["operator",{value1},{value2}]} */ protected function fun_logical_operators( &$passage ) { $this -> passage_test['main'] = __FUNCTION__; $map = $this -> get_map(); $passage['*main'] = static function ( Container $container ) use ( &$passage, $map ): bool { var_dump('logical_operators'); $logic = $map( $container, $map, $passage[0][0] ); $a = [ [ $container, $map, $passage[0][1] ], [ $container, $map, $passage[0][2] ?? [] ] ]; switch ( $logic ) { case '==': return $map( ...$a[0] ) == $map( ...$a[1] ); break; case '===': return $map( ...$a[0] ) === $map( ...$a[1] ); break; case '!=': return $map( ...$a[0] ) != $map( ...$a[1] ); break; case '<>': return $map( ...$a[0] ) <> $map( ...$a[1] ); break; case '!==': return $map( ...$a[0] ) !== $map( ...$a[1] ); break; case '<': return $map( ...$a[0] ) < $map( ...$a[1] ); break; case '>': return $map( ...$a[0] ) > $map( ...$a[1] ); break; case '<=': return $map( ...$a[0] ) <= $map( ...$a[1] ); break; case '>=': return $map( ...$a[0] ) >= $map( ...$a[1] ); break; case '<=>': return $map( ...$a[0] ) <=> $map( ...$a[1] ); break; # ----------------------------- case 'xor': return $map( ...$a[0] ) XOR $map( ...$a[1] ); break; case '!': return ! $map( ...$a[0] ); break; case '&&': return $map( ...$a[0] ) && $map( ...$a[1] ); break; case '||': return $map( ...$a[0] ) || $map( ...$a[1] ); break; } }; } PHP: [ {"logical_operators":["&&",2,{"logical_operators":["!==",2,"2"]}]} ] true P.s: Структура класса изменена
почему JSON ? JSON Код (Text): [ {"copy":["Commands",{"container":"Commands"}]}, {"copy":["Systems",{"container":"Systems"}]}, { "copy":[ "history_tags", { "method":[ {"paste":"Commands"}, "getParseTags" ] } ] }, { "method":[ {"paste":"Commands"}, "reloadDaemon", [ { "callable":[ { "method":[ {"paste":"Commands"}, "setParseTag", [ "name", { "get_results_for_keys":[ {"paste":"history_tags"}, ["name"] ] } ] ] }, { "method":[ {"paste":"Commands"}, "typeChat", [ { "get_results_for_keys":[ {"paste":"history_tags"}, ["type"] ] }, { "callable":{ "method":[ {"paste":"Commands"}, "write2chat", ["Команда принята"] ] } } ] ] } ] } ] ] }, {"copy":["getValues",{ "method":[ {"paste":"Commands"}, "getValues" ] }]}, {"copy":["time",{ "function":[ "strtotime", [ { "function":[ "sprintf", [ "+%s seconds", { "get_results_for_keys":[ {"paste":"getValues"}, [1] ] } ] ] } ] ] }]} ] YAML Код (Text): --- - copy: - Commands - container: Commands - copy: - Systems - container: Systems - copy: - history_tags - method: - paste: Commands - getParseTags - method: - paste: Commands - reloadDaemon - - callable: - method: - paste: Commands - setParseTag - - name - get_results_for_keys: - paste: history_tags - - name - method: - paste: Commands - typeChat - - get_results_for_keys: - paste: history_tags - - type - callable: method: - paste: Commands - write2chat - - Команда принята - copy: - getValues - method: - paste: Commands - getValues - copy: - time - function: - strtotime - - function: - sprintf - - "+%s seconds" - get_results_for_keys: - paste: getValues - - 1
Изначально Yaml не подходил в одной разработке. Нужно в одну строку все писать (доступен буфер обмена копи/паст)