Initial PHP Parser implementation

This commit is contained in:
Loz Calver 2016-05-18 17:38:42 +01:00 committed by Daniel Hensby
parent f225b83e2b
commit f8e3443c89
No known key found for this signature in database
GPG Key ID: B00D1E9767F0B06E
2 changed files with 96 additions and 13 deletions

View File

@ -27,6 +27,7 @@
"symfony/config": "^2.8",
"symfony/translation": "^2.8",
"vlucas/phpdotenv": "^2.4",
"nikic/php-parser": "^2.1",
"silverstripe/config": "^1@dev"
},
"require-dev": {

View File

@ -3,6 +3,9 @@
namespace SilverStripe\Core\Manifest;
use Exception;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitorAbstract;
use PhpParser\ParserFactory;
use SilverStripe\Control\Director;
/**
@ -163,6 +166,10 @@ class ClassManifest
));
}
protected $parser;
protected $traverser;
protected $visitor;
/**
* Constructs and initialises a new class manifest, either loading the data
* from the cache or re-scanning for classes.
@ -182,6 +189,11 @@ class ClassManifest
$this->cache = new $cacheClass('classmanifest'.($includeTests ? '_tests' : ''));
$this->cacheKey = 'manifest';
$this->parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP5, new PhpParser\Lexer);
$this->traverser = new NodeTraverser;
$this->traverser->addVisitor(new PhpParser\NodeVisitor\NameResolver);
$this->traverser->addVisitor($this->visitor = new SilverStripeNodeVisitor);
if (!$forceRegen && $data = $this->cache->load($this->cacheKey)) {
$this->classes = $data['classes'];
$this->descendants = $data['descendants'];
@ -593,22 +605,17 @@ class ClassManifest
}
if (!$valid) {
$tokens = token_get_all(file_get_contents($pathname));
$this->visitor->reset();
$stmts = $this->parser->parse(file_get_contents($pathname));
$this->traverser->traverse($stmts);
$classes = self::get_namespaced_class_parser()->findAll($tokens);
$traits = self::get_trait_parser()->findAll($tokens);
$classes = $this->visitor->getClasses();
$traits = $this->visitor->getTraits();
$namespace = $this->visitor->getNamespace();
$namespace = self::get_namespace_parser()->findAll($tokens);
$imports = [];//$this->getImportsFromTokens($tokens);
if ($namespace) {
$namespace = implode('', $namespace[0]['namespaceName']);
} else {
$namespace = '';
}
$imports = $this->getImportsFromTokens($tokens);
$interfaces = self::get_interface_parser()->findAll($tokens);
$interfaces = $this->visitor->getInterfaces();
$cache = array(
'classes' => $classes,
@ -722,3 +729,78 @@ class ClassManifest
}
}
}
class SilverStripeNodeVisitor extends NodeVisitorAbstract
{
private $classes = [];
private $traits = [];
private $namespace = '';
private $interfaces = [];
public function reset()
{
$this->classes = [];
$this->traits = [];
$this->namespace = '';
$this->interfaces = [];
}
public function enterNode(PhpParser\Node $node)
{
if ($node instanceof PhpParser\Node\Stmt\Class_) {
$extends = [];
$implements = [];
if ($node->extends) {
$extends[] = (string)$node->extends;
}
if ($node->implements) {
foreach ($node->implements as $implement) {
$implements[] = (string)$implement;
}
}
$this->classes[] = [
'className' => $node->name,
'extends' => $extends,
'implements' => $implements
];
} else if ($node instanceof PhpParser\Node\Stmt\Trait_) {
$this->traits[] = ['traitName' => (string)$node->name];
} else if ($node instanceof PhpParser\Node\Stmt\Namespace_) {
$this->namespace = (string)$node->name;
} else if ($node instanceof PhpParser\Node\Stmt\Interface_) {
$this->interfaces[] = ['interfaceName' => (string)$node->name];
}
if (!$node instanceof PhpParser\Node\Stmt\Namespace_) {
return NodeTraverser::DONT_TRAVERSE_CHILDREN;
}
}
public function getClasses()
{
return $this->classes;
}
public function getTraits()
{
return $this->traits;
}
public function getNamespace()
{
return $this->namespace;
}
public function getInterfaces()
{
return $this->interfaces;
}
}