Есть ли доступное решение для (повторного) генерации кода PHP из токенов Parser, возвращаемых token_get_all
? Другие решения для генерации PHP-кода также приветствуются, предпочтительно с ассоциированным лексером / парсером (если есть).
Если я не ошибаюсь, http://pear.php.net/package/PHP_Beautifier использует token_get_all (), а затем перезаписывает поток. Он использует кучи методов типа t_else
и t_close_brace
для вывода каждого токена. Возможно, вы можете захватить это для простоты.
Из моего комментария:
Кто-нибудь видит потенциальную проблему, если я просто напишу большой оператор switch, чтобы преобразовать токены обратно в свои строковые представления (т. Е. T_DO to do do), сопоставить их с токенами, соединить их с пробелами и искать какой-то код PHP довольно-печатное решение?
После некоторого поиска я нашел домашнее решение PHP в этом вопросе, которое фактически использует интерфейс PHP Tokenizer, а также некоторые инструменты форматирования кода PHP, которые более настраиваются (но для этого потребуется решение, как описано выше).
Они могут быть использованы для быстрого решения проблемы. Я вернусь сюда, когда найду время, чтобы приготовить это.
Это быстрое решение, которое я приготовил, я оставлю его здесь как часть вопроса. Обратите внимание, что для этого требуется разбить класс PHP_Beautifier, изменив все (возможно, не все, но это проще), которое является приватным для защиты , чтобы вы могли фактически использовать внутренние действия PHP_Beautifier (в противном случае было невозможно повторно использовать функциональность PHP_Beautifier без переопределения половины их кода).
Пример использования класса:
file: main.php
<?php // read some PHP code (the file itself will do) $phpCode = file_get_contents(__FILE__); // create a new instance of PHP2PHP $php2php = new PHP2PHP(); // tokenize the code (forwards to token_get_all) $phpCode = $php2php->php2token($phpCode); // print the tokens, in some way echo join(' ', array_map(function($token) { return (is_array($token)) ? ($token[0] === T_WHITESPACE) ? ($token[1] === "\n") ? "\n" : '' : token_name($token[0]) : $token; }, $phpCode)); // transform the tokens back into legible PHP code $phpCode = $php2php->token2php($phpCode); ?>
Поскольку PHP2PHP расширяет PHP_Beautifier, он обеспечивает ту же тонкую настройку под тем же API, что и PHP_Beautifier. Сам класс:
file: PHP2PHP.php
class PHP2PHP extends PHP_Beautifier { function php2token($phpCode) { return token_get_all($phpCode); } function token2php(array $phpToken) { // prepare properties $this->resetProperties(); $this->aTokens = $phpToken; $iTotal = count($this->aTokens); $iPrevAssoc = false; // send a signal to the filter, announcing the init of the processing of a file foreach($this->aFilters as $oFilter) $oFilter->preProcess(); for ($this->iCount = 0; $this->iCount < $iTotal; $this->iCount++) { $aCurrentToken = $this->aTokens[$this->iCount]; if (is_string($aCurrentToken)) $aCurrentToken = array( 0 => $aCurrentToken, 1 => $aCurrentToken ); // ArrayNested->off(); $sTextLog = PHP_Beautifier_Common::wsToString($aCurrentToken[1]); // ArrayNested->on(); $sTokenName = (is_numeric($aCurrentToken[0])) ? token_name($aCurrentToken[0]) : ''; $this->oLog->log("Token:" . $sTokenName . "[" . $sTextLog . "]", PEAR_LOG_DEBUG); $this->controlToken($aCurrentToken); $iFirstOut = count($this->aOut); //5 $bError = false; $this->aCurrentToken = $aCurrentToken; if ($this->bBeautify) { foreach($this->aFilters as $oFilter) { $bError = true; if ($oFilter->handleToken($this->aCurrentToken) !== FALSE) { $this->oLog->log('Filter:' . $oFilter->getName() , PEAR_LOG_DEBUG); $bError = false; break; } } } else { $this->add($aCurrentToken[1]); } $this->controlTokenPost($aCurrentToken); $iLastOut = count($this->aOut); // set the assoc if (($iLastOut-$iFirstOut) > 0) { $this->aAssocs[$this->iCount] = array( 'offset' => $iFirstOut ); if ($iPrevAssoc !== FALSE) $this->aAssocs[$iPrevAssoc]['length'] = $iFirstOut-$this->aAssocs[$iPrevAssoc]['offset']; $iPrevAssoc = $this->iCount; } if ($bError) throw new Exception("Can'process token: " . var_dump($aCurrentToken)); } // ~for // generate the last assoc if (count($this->aOut) == 0) throw new Exception("Nothing on output!"); $this->aAssocs[$iPrevAssoc]['length'] = (count($this->aOut) -1) - $this->aAssocs[$iPrevAssoc]['offset']; // post-processing foreach($this->aFilters as $oFilter) $oFilter->postProcess(); return $this->get(); } } ?>
В категории «другие решения» вы можете попробовать PHP Parser .
Парсер превращает исходный код PHP в абстрактное синтаксическое дерево …. Кроме того, вы можете преобразовать дерево синтаксиса обратно в PHP-код.
Смотрите наш внешний интерфейс PHP . Это полный парсер PHP, автоматически создающий АСТ и соответствующий симпатичный принттер, который регенерирует компилируемый PHP-код в комплекте с исходными коммитами. (EDIT 12/2011: см. Этот ответ «SO» для получения более подробной информации о том, что нужно для отпечатка от AST, которые представляют собой только организованную версию токенов: https://stackoverflow.com/a/5834775/120163 )
Передняя часть встроена в наш DMS Software Reengineering Toolkit , что позволяет анализировать и преобразовывать PHP AST (а затем через код niceprinter).