<?php
/**
* @package s9e\TextFormatter
* @copyright Copyright (c) 2010-2021 The s9e authors
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
*/
namespace s9e\TextFormatter\Configurator\RendererGenerators\PHP;
abstract class AbstractOptimizer
{
/**
* @var integer Number of tokens
*/
protected $cnt;
/**
* @var integer Current token index
*/
protected $i;
/**
* @var boolean Whether the tokens have been changed
*/
protected $changed;
/**
* @var array Tokens from current source
*/
protected $tokens;
/**
* Optimize the control structures of a script
*
* Removes brackets in control structures wherever possible. Prevents the generation of EXT_STMT
* opcodes where they're not strictly required.
*
* @param string $php Original code
* @return string Optimized code
*/
public function optimize($php)
{
$this->reset($php);
$this->optimizeTokens();
// Rebuild the source if it has changed
if ($this->changed)
{
$php = $this->serialize();
}
// Free the memory taken up by the tokens
unset($this->tokens);
return $php;
}
/**
* Optimize the stored tokens
*
* @return void
*/
abstract protected function optimizeTokens();
/**
* Reset the internal state of this optimizer
*
* @param string $php PHP source
* @return void
*/
protected function reset($php)
{
$this->tokens = token_get_all('<?php ' . $php);
$this->i = 0;
$this->cnt = count($this->tokens);
$this->changed = false;
}
/**
* Serialize the tokens back to source
*
* @return string
*/
protected function serialize()
{
// Remove the first token, which should be T_OPEN_TAG, aka "<?php"
unset($this->tokens[0]);
$php = '';
foreach ($this->tokens as $token)
{
$php .= (is_string($token)) ? $token : $token[1];
}
return $php;
}
/**
* Move the internal cursor until it reaches given string
*
* @param string $str String to reach
* @return void
*/
protected function skipToString($str)
{
while (++$this->i < $this->cnt && $this->tokens[$this->i] !== $str);
}
/**
* Skip all whitespace
*
* @return void
*/
protected function skipWhitespace()
{
while (++$this->i < $this->cnt && $this->tokens[$this->i][0] === T_WHITESPACE);
}
/**
* Remove one tab of indentation off a range of PHP tokens
*
* @param integer $start Index of the first token to unindent
* @param integer $end Index of the last token to unindent
* @return void
*/
protected function unindentBlock($start, $end)
{
$this->i = $start;
do
{
if ($this->tokens[$this->i][0] === T_WHITESPACE || $this->tokens[$this->i][0] === T_DOC_COMMENT)
{
$this->tokens[$this->i][1] = preg_replace("/^\t/m", '', $this->tokens[$this->i][1]);
}
}
while (++$this->i <= $end);
}
}