[ ] Codeigniter Framework AST |
, , 100 Codeigniter. , 3 . , . .
Codeigniter -, .
, , .
. . php ( Codeigniter).
, , , php -.
. , , . . , .
Codeigniter , . .
50 ( get_included_files
).
, :
30 , , , +- 35 . php . , 900 .
, , , 1 (30%) +-2 :
Loading Time: Base Classes 0.0274
Controller Execution Time 1.9403
Total Execution Time 1.9687
, 900 , php.
, "" , .
twig
smarty
, , .
AST .
- :
...
...
$this->load->view(string $templatePath,array $params)
"include" $params
, inline
. .
, : Nikic PHP-Parser. php . php - - php 5.2+.
PHP-Parser AST: NodeVisitor NodeTraverser .
view
load
, . NodeVisitor. leaveNode(Node $node)
NodeTraverser
"" AST:
class MyNodeVisitor extends NodeVisitorAbstract {
public function leaveNode(Node $node) {
// -
if ($node instanceof Node\Expr\MethodCall) {
// ,
if ($node->name == 'view') {
//
// Codeigniter'a,
// :)
// , .
// - ,
// ,
if ($node->args[0]->value instanceof \PhpParser\Node\Scalar\String_) {
// ,
$code = md5(mt_rand(0, 7219832) . microtime(true));
$node->name = 'to_be_changed_' . $code;
$params = null;
// , `inline`
if (count($node->args) > 1) {
if ($node->args[1]->value instanceof Node\Expr\Array_) {
$params = new Node\Expr\Array_($node->args[1]->value->items, [
'kind' => Node\Expr\Array_::KIND_SHORT,
]);
} else {
if ($node->args[1]->value->name != 'this') {
$params = $node->args[1]->value;
}
}
}
// ,
//
$this->nodesToSubstitute[] = new TemplateReference($this->nodeIndex, $node->args[0]->value->value, $params, $code);
}
}
...
. : require, include ..
. , PHP-Parser :
class CodeigniterTemplateOptimizer {
private $optimizedFiles = [];
private $parser;
private $traverser;
private $prettyPrinter;
private $factory;
private $myVisitor;
private $templatesFolder = '';
public function __construct(string $templatesFolder) {
$this->parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP5);
$this->traverser = new MyNodeTraverser();
$this->prettyPrinter = new PrettyPrinter\Standard();
$this->factory = new BuilderFactory();
$this->templatesFolder = $templatesFolder;
$this->myVisitor = new MyNodeVisitor();
$this->traverser->addVisitor($this->myVisitor);
}
public function optimizeTemplate(string $relativePath, $depth = 0, $keepOptimizing = true) {
if (substr($relativePath, -4, 4) !== '.php') {
$relativePath .= '.php';
}
if (!isset($this->optimizedFiles[$relativePath])) {
$templatePath = $this->templatesFolder . $relativePath;
if (file_exists($templatePath)) {
$templateOffset = 0;
$notOptimized = file_get_contents($templatePath);
// AST
$stmts = $this->parser->parse($notOptimized);
if ($keepOptimizing) {
$this->myVisitor->clean();
$this->traverser->setCurrentWorkingFile($relativePath);
// AST
$stmts = $this->traverser->traverse($stmts);
// MyNodeVisitor
$inlineTemplateReference = $this->myVisitor->getNodesToSubstitute();
++$depth;
$stmsBefore = count($stmts);
foreach ($inlineTemplateReference as $ref) {
// -
$nestedTemplateStatements = $this->optimizeTemplate($ref->relativePath, $depth);
$subtempalteLength = count($nestedTemplateStatements);
$insertOffset = $ref->nodeIndex + $templateOffset;
$pp = new PrettyPrinter\Standard();
// `inline`: `extract`
if ($ref->paramsNodes) {
array_unshift($nestedTemplateStatements, new Node\Expr\FuncCall(new Node\Name('extract'), [$ref->paramsNodes]));
}
// ,
if (get_class($stmts[$insertOffset]) === 'PhpParser\Node\Expr\MethodCall' && ($stmts[$insertOffset]->name === "to_be_changed_" . $ref->code)) {
// "" AST
// if(1),
$stmts[$insertOffset] = new Node\Stmt\If_(new Node\Scalar\LNumber(1), [
'stmts' => $nestedTemplateStatements
]);
} else {
// , ast
}
}
}
// "" .
//
$this->optimizedFiles[$relativePath] = $stmts;
} else {
throw new Exception("File not exists `" . $templatePath . "` when optimizing templates");
}
}
//
return $this->optimizedFiles[$relativePath];
}
public function writeToFile(string $filePath, $nodes) {
$code = $this->prettyPrinter->prettyPrintFile($nodes);
// create directories in a path if they not exists
if (!is_dir(dirname($filePath))) {
mkdir(dirname($filePath), 0755, true);
}
// write to file
file_put_contents($filePath, $code);
}
}
, :
// -
$optimizer = new CodeigniterTemplateOptimizer('./views/');
//
$optimizer->writeToFile($to, $optimizer->optimizeTemplate($from));
DirectoryIterator
.
, 1 , Codeigniter:
Loading Time: Base Classes 0.0229
Controller Execution Time 0.7975
Total Execution Time 0.8215
php-. . ( "") .
.