Last active
August 29, 2015 14:15
-
-
Save jderusse/32a9d0b105e359f322af to your computer and use it in GitHub Desktop.
melody-extensions
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 | |
<<<CONFIG | |
packages: | |
- "nikic/php-parser" | |
CONFIG; | |
/** | |
* Browse the current working directory to search called function. | |
* Then render the list of functions grouped by extension name. | |
* | |
* Usage : | |
* $ cd /path/to/your/project | |
* $ melody run 32a9d0b105e359f322af [ReportType] | |
* | |
* With ReportType: | |
* - "full" Display files group by function group by extension | |
* - "function" Display function group by extension | |
* - "file" Display files group by extension | |
* - "extension" Display extensions | |
**/ | |
$reportName = ucfirst(strtolower(isset($argv[1]) ? $argv[1] : 'File')); | |
$reportClass = $reportName . 'Report'; | |
if (!class_exists($reportClass)) { | |
die('Unkown repport ' . $reportName . PHP_EOL); | |
} | |
class FunctionCallVisitor extends PhpParser\NodeVisitorAbstract | |
{ | |
private $collector; | |
public function __construct(Collector $collector) | |
{ | |
$this->collector = $collector; | |
} | |
public function leaveNode(PhpParser\Node $node) | |
{ | |
if ($node instanceof PhpParser\Node\Stmt\Function_) { | |
$this->collector->addStmtFunction(strtolower($node->name)); | |
} elseif ($node instanceof PhpParser\Node\Expr\FuncCall && $node->name instanceof PhpParser\Node\Name) { | |
$this->collector->addCalledFunction(strtolower($node->name)); | |
} | |
} | |
} | |
class Called | |
{ | |
public $file; | |
public $functionName; | |
public function __construct($file, $functionName) | |
{ | |
$this->file = $file; | |
$this->functionName = $functionName; | |
} | |
} | |
class Collector | |
{ | |
private $currentFile; | |
private $stmtFunctions = array(); | |
private $called = array(); | |
public function setCurrentFile($file) | |
{ | |
$this->currentFile = $file; | |
} | |
public function addCalledFunction($functionName) | |
{ | |
if (!in_array($functionName, $this->stmtFunctions)) { | |
$this->called[sprintf('%s :: %s', $this->currentFile, $functionName)] = new Called($this->currentFile, $functionName); | |
} | |
} | |
public function addStmtFunction($functionName) | |
{ | |
if (!in_array($functionName, $this->stmtFunctions)) { | |
$this->stmtFunctions[] = $functionName; | |
$this->called = array_filter($this->called, function ($called) use ($functionName) { | |
return $called->functionName !== $functionName; | |
}); | |
} | |
} | |
public function getData() | |
{ | |
$phpFunctions = array(); | |
foreach (get_loaded_extensions() as $extension) { | |
if (false !== $functions = get_extension_funcs($extension)) { | |
foreach ($functions as $function) { | |
$phpFunctions[$function] = $extension; | |
} | |
} | |
} | |
$data = array(); | |
foreach ($this->called as $called) { | |
if (isset($phpFunctions[$called->functionName])) { | |
$data[$phpFunctions[$called->functionName]][$called->functionName][] = $called->file; | |
} else { | |
$data['?'][$called->functionName][] = $called->file; | |
} | |
} | |
ksort($data); | |
foreach ($data as & $extensionData) { | |
ksort($extensionData); | |
foreach ($extensionData as & $functionData) { | |
sort($functionData); | |
} | |
} | |
return $data; | |
} | |
} | |
abstract class Report | |
{ | |
protected $collectedData; | |
public function __construct(array $collectedData, array $excludedExtension = array('Core', 'standard')) | |
{ | |
foreach ($excludedExtension as $extension) { | |
unset($collectedData[$extension]); | |
} | |
$this->collectedData = $collectedData; | |
} | |
abstract public function render(); | |
} | |
class FullReport extends Report | |
{ | |
public function render() | |
{ | |
foreach ($this->collectedData as $extension => $extensionData) { | |
echo $extension, PHP_EOL; | |
foreach ($extensionData as $functionName => $functionData) { | |
echo ' ', $functionName, PHP_EOL; | |
foreach ($functionData as $fileName) { | |
echo ' ', $fileName, PHP_EOL; | |
} | |
} | |
} | |
} | |
} | |
class FileReport extends Report | |
{ | |
public function render() | |
{ | |
foreach ($this->collectedData as $extension => $extensionData) { | |
echo $extension, PHP_EOL; | |
if ($extension === '?') { | |
foreach ($extensionData as $functionName => $functionData) { | |
echo ' ', $functionName, PHP_EOL; | |
foreach ($functionData as $fileName) { | |
echo ' ', $fileName, PHP_EOL; | |
} | |
} | |
} else { | |
$files = call_user_func_array('array_merge', array_values($extensionData)); | |
array_unique($files); | |
foreach ($files as $fileName) { | |
echo ' ', $fileName, PHP_EOL; | |
} | |
} | |
} | |
} | |
} | |
class FunctionReport extends Report | |
{ | |
public function render() | |
{ | |
foreach ($this->collectedData as $extension => $extensionData) { | |
echo $extension, PHP_EOL; | |
foreach (array_keys($extensionData) as $functionName) { | |
echo ' ', $functionName, PHP_EOL; | |
} | |
} | |
} | |
} | |
class ExtensionReport extends Report | |
{ | |
public function render() | |
{ | |
foreach ($this->collectedData as $extension => $extensionData) { | |
echo $extension, PHP_EOL; | |
if ($extension === '?') { | |
foreach (array_keys($extensionData) as $functionName) { | |
echo ' ', $functionName, PHP_EOL; | |
} | |
} | |
} | |
} | |
} | |
$collector = new Collector(); | |
$inDir = getcwd(); | |
$parser = new PhpParser\Parser(new PhpParser\Lexer\Emulative); | |
$traverser = new PhpParser\NodeTraverser; | |
$traverser->addVisitor(new FunctionCallVisitor($collector)); | |
// iterate over all .php files in the directory | |
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($inDir)); | |
$files = new RegexIterator($files, '/\.php$/'); | |
function format_size($size) | |
{ | |
$unit=array('o', 'kio', 'Mio', 'Gio', 'Tio', 'Pio'); | |
return sprintf('mem %01.1f %s', $size/pow(1024, ($i=floor(log($size, 1024)))), $unit[$i]); | |
} | |
foreach ($files as $file) { | |
echo sprintf("\r%-64.64s %15s", substr($file, strlen($inDir)), format_size(memory_get_usage())); | |
$collector->setCurrentFile((string) $file); | |
try { | |
$code = file_get_contents($file); | |
$stmts = $parser->parse($code); | |
// traverse | |
$stmts = $traverser->traverse($stmts); | |
} catch (PhpParser\Error $e) { | |
echo PHP_EOL, $file, 'Parse Error: ', $e->getMessage(), PHP_EOL; | |
} | |
} | |
echo sprintf("\r%-80.80s\r", ''); | |
$report = new $reportClass($collector->getData()); | |
$report->render(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment