-

   rss_rss_hh_new

 - e-mail

 

 -

 LiveInternet.ru:
: 17.03.2011
:
:
: 51

:


[ ] Codeigniter Framework AST

, 07 2017 . 14:10 +

, , 100 Codeigniter. , 3 . , . .



Codeigniter -, .
, , .


. . php ( Codeigniter).


, , , php -.


. , , . . , .



Codeigniter , . .


50 ( get_included_files).


, :


image


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-. . ( "") .


.

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335080/

:  

: [1] []
 

:
: 

: ( )

:

  URL