Skip to content

Instantly share code, notes, and snippets.

@trevordixon
Last active December 14, 2015 08:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save trevordixon/5061718 to your computer and use it in GitHub Desktop.
Save trevordixon/5061718 to your computer and use it in GitHub Desktop.
PHP Script to find non-static methods being called as if they were static. Uses https://github.com/nikic/PHP-Parser.
<?php
require 'PHP-Parser/lib/bootstrap.php';
ini_set('memory_limit', '512M');
// Feeds the given file to the PHP parser to be parsed and analyzed
function analyze_file($path, $parser, $traverser, $visitor) {
$code = file_get_contents($path);
$visitor->setFile($path);
$stmts = $parser->parse($code);
$stmts = $traverser->traverse($stmts);
}
// Feeds PHP files to analyze_file; recurses through subdirectories
function visit_dir($path, $parser, $traverser, $visitor) {
$list = scandir($path);
foreach($list as $p) {
if ($p == '.' || $p == '..') continue;
$full_path = $path . '/' . $p;
if (is_link($full_path)) $full_path = readlink($full_path);
if (is_file($full_path)) {
$ext = pathinfo($full_path, PATHINFO_EXTENSION);
if ($ext != 'php' && $ext != 'class') continue;
analyze_file($full_path, $parser, $traverser, $visitor);
//echo $full_path . "\n";
} else if (is_dir($full_path)) {
visit_dir($full_path, $parser, $traverser, $visitor);
}
}
}
// Records class and method declarations and static method calls
class ClassAnalyzer extends PHPParser_NodeVisitorAbstract {
private $current_class;
public $classes = array();
public $static_calls = array();
private $file;
public function enterNode(PHPParser_Node $node) {
if ($node instanceof PHPParser_Node_Stmt_Class) {
$name = $node->name;
if (!array_key_exists($name, $this->classes)) {
$this->classes[$name] = array();
$this->current_class = $node->name;
} else {
// Class alread defined
}
} else if ($node instanceof PHPParser_Node_Stmt_ClassMethod) {
$name = $node->name;
$this->classes[$this->current_class][$name] = ($node->type >= 8) ? 'static' : 'instance';
} else if ($node instanceof PHPParser_Node_Expr_StaticCall) {
$this->static_calls[] = array(
'file' => $this->file,
'line' => $node->getLine(),
'class' => $node->class->parts[0],
'method' => $node->name
);
}
}
public function setFile($file) {
$this->file = $file;
}
}
// Kicks it all off
$paths = $argv;
array_shift($paths);
$parser = new PHPParser_Parser(new PHPParser_Lexer);
$findClasses = new PHPParser_NodeTraverser;
$classAnalyzer = new ClassAnalyzer;
$findClasses->addVisitor($classAnalyzer);
foreach ($paths as $path) {
$path = realpath($path);
echo "Scanning $path\n";
visit_dir($path, $parser, $findClasses, $classAnalyzer);
}
echo "\n";
// Prints static method calls to non-static methods
foreach ($classAnalyzer->static_calls as $call) {
$type = @$classAnalyzer->classes[$call['class']][$call['method']];
if ($type == 'instance') {
echo $call['file'] . ':' . $call['line'] . "\t" . $call['class'] . '::' . $call['method'] . "\n";
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment