E.g. this may speed up UnionTypeVisitor, ParseVisitor, and BlockAnalysisVisitor.
Also, making PreOrderAnalysisVisitor and PostOrderAnalysisVisitor into traits (and renaming visitAssign to postOrderVisitAssign, etc) may also improve performance.
$this can be reused
visitAssign can call postOrderVisitAssign, preOrderVisitAssign directly.
visit(Context $context, Node $node, ?Node $parent_node) is probably more efficient
<?php
// Took 0.001199 (For ObjectVisitor) vs 0.000682 (For SameObjectVisitor) : iterations=100
// (58% of the time)
use ast\Node;
class TestCodebase {
}
class TestContext {
public $visits = 0;
}
class ObjectVisitor {
private $code_base;
private $context;
public function __construct(TestCodeBase $code_base, TestContext $context) {
$this->code_base = $code_base;
$this->context = $context;
}
public function visitA(Node $node) : TestContext {
$context = $this->context;
$context->visits += 10;
foreach ($node->children as $child_node) {
if (!($child_node instanceof Node)) {
continue;
}
(new ObjectVisitor($this->code_base, $context))->{$node->kind % 2 === 1 ? 'visitA' : 'visitB'}($child_node);
}
return $context;
}
public function visitB(Node $node) : TestContext {
$context = $this->context;
$context->visits++;
foreach ($node->children as $child_node) {
if (!($child_node instanceof Node)) {
continue;
}
(new ObjectVisitor($this->code_base, $context))->{$node->kind % 2 === 1 ? 'visitA' : 'visitB'}($child_node);
}
return $context;
}
}
class SameObjectVisitor {
private $code_base;
public function __construct(TestCodeBase $code_base) {
$this->code_base = $context;
}
public function visitA(TestContext $context, Node $node) : TestContext {
$context->visits+= 10;
foreach ($node->children as $child_node) {
if (!($child_node instanceof Node)) {
continue;
}
$this->{$node->kind % 2 === 1 ? 'visitA' : 'visitB'}($context, $child_node);
}
return $context;
}
public function visitB(TestContext $context, Node $node) : TestContext {
$context->visits++;
foreach ($node->children as $child_node) {
if (!($child_node instanceof Node)) {
continue;
}
$this->{$node->kind % 2 === 1 ? 'visitA' : 'visitB'}($context, $child_node);
}
return $context;
}
}
function run_object(TestCodeBase $code_base, Node $root) : TestContext{
$context = new TestContext();
return (new ObjectVisitor($code_base, $context))->visitA($root);
}
function run_recursive(TestCodeBase $code_base, Node $root) : TestContext{
$context = new TestContext();
return (new SameObjectVisitor($code_base))->visitA($context, $root);
}
const ITERATION_COUNT = 100;
function main() {
$ast = \ast\parse_file(__DIR__ . '/src/Phan/Analysis/PostOrderAnalysisVisitor.php', 50);
$code_base = new TestCodeBase();
$start = microtime(true);
for ($i = 0; $i < ITERATION_COUNT; $i++) {
run_object($code_base, $ast);
}
$end = microtime(true);
$start2 = microtime(true);
for ($i = 0; $i < ITERATION_COUNT; $i++) {
run_recursive($code_base, $ast);
}
$end2 = microtime(true);
printf("Took %.6f vs %.6f : iterations=%d\n", ($end-$start)/ITERATION_COUNT, ($end2-$start2)/ITERATION_COUNT, ITERATION_COUNT);
}
main();
E.g. this may speed up UnionTypeVisitor, ParseVisitor, and BlockAnalysisVisitor.
Also, making PreOrderAnalysisVisitor and PostOrderAnalysisVisitor into traits (and renaming visitAssign to postOrderVisitAssign, etc) may also improve performance.
$this
can be reused