生成PHP代码(来自Parser Tokens)

时间:2011-02-21 16:11:52

标签: php code-generation tokenize

是否有任何可用的解决方案(重新)从Parser Tokens返回的token_get_all生成PHP代码?其他用于生成PHP代码的解决方案也是受欢迎的,最好使用相关的词法分析器/解析器(如果有的话)。

4 个答案:

答案 0 :(得分:2)

来自我的评论:

  

有没有人看到潜在的问题,   如果我只是写一个大开关   将令牌转换回来的声明   他们的字符串表示(即   T_DO到'do'),映射到   代币,加入空格,寻找   某种PHP代码漂亮的打印   溶液

经过一番研究,我在this问题中找到了一个PHP自制解决方案,它实际上使用了PHP Tokenizer接口,以及一些更易配置的PHP代码格式化工具(但需要如上所述的解决方案) )。

这些可用于快速实现解决方案。当我找到一些时间来烹饪时,我会回到这里。


使用PHP_Beautifier

的解决方案

这是我制作的快速解决方案,我将把它留在这里作为问题的一部分。请注意,它要求您打破PHP_Beautifier类,通过更改私有 protected 的所有内容(可能不是所有内容,但这更容易),以允许您实际使用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,它允许在PHP_Beautifier使用的相同API下进行相同的微调。课程本身是:

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();
  }
}
?>

答案 1 :(得分:2)

在“其他解决方案”类别中,您可以尝试PHP Parser

  

解析器将PHP源代码转换为抽象语法树....此外,您可以将语法树转换回PHP代码。

答案 2 :(得分:1)

如果我没有弄错http://pear.php.net/package/PHP_Beautifier使用token_get_all()然后重写流。它使用大量方法(如t_elset_close_brace)输出每个标记。也许你可以为了简单而劫持这个。

答案 3 :(得分:-2)

请参阅我们的PHP Front End。它是一个完整的PHP解析器,自动构建AST,以及一个匹配的prettyprinter,它可以使用原始通信重新生成可编译的PHP代码。 (编辑12/2011: 请参阅此SO答案,了解有关从ASTs中进行漂亮打印所需的更多详细信息,这只是令牌的有组织版本:https://stackoverflow.com/a/5834775/120163

前端建立在我们的DMS Software Reengineering Toolkit之上,可以分析和转换PHP AST(然后通过prettyprinter代码)。