Last active
December 14, 2015 08:59
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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