Отредактировал немного, сейчас работает лучше, но в принципе - наверное лучше в класс перетащить, а то 3 анонимные функции как-то криво начинают выглядеть.
<?php
$source = <<<'code'
<?php
$name = 'anon';
echo '<h2>';
echo 'Number is: ';
echo count(["1","2","3"]);
echo '</h2>';
echo 'CHECK
';
echo 1 + 3 . '-'. 4 . '=' . 0;
echo '
';
echo '<h2>';
echo 'Olololo';
echo '</h2>';
echo '
';
echo '<h3>';
echo 'QWErty';
echo '</h3>';
echo '
';
echo '<h2>';
echo 'Hello, ';
echo $name;
echo '</h2>';
echo '
';
foreach ([1,2,3] as $item) {
echo '
';
echo '<h2>';
echo 'Number is: ';
echo $item;
echo '</h2>';
echo '
';
}
code;
$tokens = token_get_all($source);
$last_token=false;
$getnext=function() use (&$tokens, &$last_token){
$token=array_shift($tokens);
if(is_null($token)) return false;
if(is_array($token)){
$last_token= token_name($token[0]);
return $token[1];
} else {
$last_token='';
return $token;
}
};
$getbracket=function($bracket) use (&$tokens,$getnext,&$last_token){
$stack=[]; $buf=$bracket;
if($bracket=='[') array_unshift($stack,']');
if($bracket=='(') array_unshift($stack,')');
while(false!==($x=$getnext())){
$buf.=$x;
if($x==$stack[0]){
array_shift($stack);
if(count($stack)==0) break;
}
if($x=='(') array_unshift($stack,')');
if($x=='{') array_unshift($stack,'}');
if($x=='[') array_unshift($stack,']');
}
return $buf;
};
$getecho=function() use (&$tokens,$getnext,$getbracket,&$last_token){
$buf='';
$buf2='';
$waitecho=false;
while(false!==($x=$getnext())){
//echo '{'.$last_token.' '.$x.'}';
if($last_token==='' && $x==';'){
$waitecho=true;
$buf2.=$x;
} elseif($last_token==='T_ECHO' && $waitecho){ // склеиваем
$waitecho=false;
$buf.=',';$buf2='';
} elseif($last_token==='T_WHITESPACE' && $waitecho){
$buf2.=$x;
} else if($waitecho){
return $buf.$buf2.$x;
} else if($last_token==='T_CONSTANT_ENCAPSED_STRING') {// склеиваем константные строки с одинаковыми кавычками
$s=$x[0];
$y = preg_replace('~'.preg_quote($s,"~'").'\s*[\.\,]\s*$~', '', $buf, 1, $count);
if($count>0)
$buf=$y.substr($x,1);
else
$buf.=$x;
} else if($last_token==='' && in_array($x,['[','('])) {
$buf.=$getbracket($x);
} else {
$buf.=$x;
}
};
return '';
};
while(false!==($x=$getnext())) {
echo $x;
if($last_token=='T_ECHO'){
echo $getecho();
}
}
?>
<?php
$name = 'anon';
echo '<h2>Number is: ', count(["1","2","3"]), '</h2>CHECK
', 1 + 3 . '-'. 4 . '=' . 0, '
<h2>Olololo</h2>
<h3>QWErty</h3>
<h2>Hello, ', $name, '</h2>
';
foreach ([1,2,3] as $item) {
echo '
<h2>Number is: ', $item, '</h2>
';
}