Skip to content

Instantly share code, notes, and snippets.

@xeoncross
Last active August 29, 2015 14:00
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 xeoncross/11190461 to your computer and use it in GitHub Desktop.
Save xeoncross/11190461 to your computer and use it in GitHub Desktop.
Wordpress parser to make a lightweight wordpress using the PHP-Parser by nikic

Wordpress Light

This is an attempt to remove a lot of cruft from wordpress by using the PHP-Parser to automate changing and/or removing parts of the code from the wordpress core and then saving the resulting system back to the file system as a new, lighter wordpress.

Wordpress could also do with a bit of auto-loading rather than the load-it-all-and-see-if-we-need-it approach they have been using.

{
"require": {
"nikic/php-parser": "1.0.*@dev"
}
}
<?php
// https://github.com/nikic/PHP-Parser/blob/master/lib/PhpParser/NodeVisitor.php
use PhpParser\Node;
use PhpParser\Node\Stmt;
class MyNodeVisitor extends PHPParser_NodeVisitorAbstract {
public $internal = array();
public $replacements = array();
public $blocks = array();
public $types = array(
'class' => '\PhpParser\Node\Stmt\Class_',
'interface' => '\PhpParser\Node\Stmt\Interface_',
'function' => '\PhpParser\Node\Stmt\Function_',
'const' => '\PhpParser\Node\Stmt\Const_',
'trait' => '\PhpParser\Node\Stmt\Trait_',
//'namespace' => 'PhpParser\Node\Stmt\Namespace_'
);
public $inside_block = false;
/**
* We want to compare the user-defined functions to internal functions later
*/
public function __construct()
{
$functions = get_defined_functions();
$this->internal = array_flip($functions['internal']);
}
/**
* We need to catch raw PHP code not inside a function/class
*/
public function enterNode(PHPParser_Node $node)
{
foreach($this->types as $type => $class) {
if($node instanceof $class) {
$this->inside_block = true;
}
}
}
/**
* When leaving a node we want to replace method/function names with new ones and
* store whatever type of block this node is with the blocks array
*/
public function leaveNode(PHPParser_Node $node)
{
//var_dump(get_class($node), array_keys((array)$node));
//return;
// https://github.com/nikic/PHP-Parser/blob/master/lib/PhpParser/Node/Name.php
if ($node->name instanceof \PHPParser\Node\Name) {
// static function name
if($node->namespacedName) {
$name = $node->namespacedName->toString('/');
} else {
$name = (string) $node->name;
}
} else {
// dynamic function name
$name = false;
}
// Might need to replace function calls
if ($node instanceof \PHPParser\Node\Expr\FuncCall) {
// Except closures...
if( ! $name) {
return;
}
// and normal PHP functions...
if(isset($this->internal[$name])) {
return;
}
if(isset($this->replacements[$name])) {
$replacement = $this->replacements[$name];
if(is_array($replacement)) {
// https://github.com/nikic/PHP-Parser/blob/master/lib/PhpParser/Node/Expr/MethodCall.php
return new PHPParser_Node_Expr_MethodCall(
new PHPParser_Node_Name_FullyQualified($replacement[0]),
$replacement[1],
$node->args
);
} elseif(strpos($replacement, '::') !== false) {
list($class, $method) = explode('::', $replacement, 2);
// https://github.com/nikic/PHP-Parser/blob/master/lib/PhpParser/Node/Expr/StaticCall.php
return new PHPParser_Node_Expr_StaticCall(
new PHPParser_Node_Name_FullyQualified($class),
$method,
$node->args
);
} else {
// https://github.com/nikic/PHP-Parser/blob/master/lib/PhpParser/Node/Expr/FuncCall.php
return new PHPParser_Node_Expr_FuncCall(
new PHPParser_Node_Name_FullyQualified($class),
$node->args
);
}
}
}
if($node instanceof \PhpParser\Node\Stmt) {
// Capture each block type
foreach($this->types as $type => $class) {
if($node instanceof $class) {
$this->inside_block = false;
if(empty($this->blocks[$type])) {
$this->blocks[$type] = array();
}
$prettyPrinter = new PhpParser\PrettyPrinter\Standard;
$code = $prettyPrinter->prettyPrint([$node]);
$this->blocks[$type][$name] = $code;
//print "$type $name\n";
return;
}
}
}
if( ! $this->inside_block) {
$prettyPrinter = new PhpParser\PrettyPrinter\Standard;
$code = $prettyPrinter->prettyPrint([$node]);
$this->blocks['code']['code'] = $code;
}
}
}
/*
// Record classes
if($node instanceof Stmt\Class_ OR $node instanceof Stmt\Interface_) {
$prettyPrinter = new PhpParser\PrettyPrinter\Standard;
$code = $prettyPrinter->prettyPrint([$node]);
$this->classes[$name] = $code;
print "Class $name\n";
return;
}
// Record functions
if($node instanceof Stmt\Function_) {
$prettyPrinter = new PhpParser\PrettyPrinter\Standard;
$code = $prettyPrinter->prettyPrint([$node]);
$this->functions[$name] = $code;
print "function $name\n";
}
*/
/*
// https://github.com/nikic/PHP-Parser/blob/master/lib/PhpParser/Node/Name.php
if ($node->name instanceof PHPParser_Node_Name) {
// static function name
$type = 'static';
} else {
// dynamic function name
$type = 'dynamic';
}
if(empty($this->functions[$type][$name])) {
$this->functions[$type][$name] = 0;
}
$this->functions[$type][$name]++;
*/
/*
public function leaveNode(Node $node) {
if($node instanceof Stmt\Class_) {
$this->class = null;
}
}
/* Convert namespace to _ for old systems
public function leaveNode(Node $node) {
if ($node instanceof Node\Name) {
return new Node\Name($node->toString('_'));
} elseif ($node instanceof Stmt\Class_
|| $node instanceof Stmt\Interface_
|| $node instanceof Stmt\Function_) {
$node->name = $node->namespacedName->toString('_');
} elseif ($node instanceof Stmt\Const_) {
foreach ($node->consts as $const) {
$const->name = $const->namespacedName->toString('_');
}
} elseif ($node instanceof Stmt\Namespace_) {
// returning an array merges is into the parent array
return $node->stmts;
} elseif ($node instanceof Stmt\Use_) {
// returning false removed the node altogether
return false;
}
}
*/
<?php
const IN_DIR = 'wordpress/';
const OUT_DIR = 'public/';
chdir(__DIR__);
require('vendor/autoload.php');
require('MyNodeVisitor.php');
$replacements = require('replacements.php');
ini_set('xdebug.max_nesting_level', 2000);
$parser = new PhpParser\Parser(new PhpParser\Lexer);
$traverser = new PhpParser\NodeTraverser;
$prettyPrinter = new PhpParser\PrettyPrinter\Standard;
$NameResolver = new PhpParser\NodeVisitor\NameResolver;
$nodeVisitor = new MyNodeVisitor();
$nodeVisitor->replacements = $replacements;
// add your visitor
$traverser->addVisitor($NameResolver);
$traverser->addVisitor($nodeVisitor);
// iterate over all .php files in the directory
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(IN_DIR));
$files = new RegexIterator($files, '/\.php$/');
$x = 0;
foreach ($files as $file) {
if($x++ > 6) {
//break;
}
try {
print "$x:$file\n";
// Remove starting directory
$relative_path = substr($file, strlen(IN_DIR));
// read the file that should be converted
$code = file_get_contents($file);
// parse
$stmts = $parser->parse($code);
// traverse
$stmts = $traverser->traverse($stmts);
/*
// pretty print
$code = '<?php ' . $prettyPrinter->prettyPrint($stmts);
$directory = OUT_DIR . dirname($relative_path);
if ( ! is_dir($directory)) {
if( ! mkdir($directory, 0777, true)) {
print "Couldn't make: $directory\n";
continue;
}
}
file_put_contents(OUT_DIR . $relative_path, $code);
*/
//if($x>2) { print_r($nodeVisitor->blocks);die(); }
foreach($nodeVisitor->blocks as $type => $blocks) {
foreach($blocks as $name => $block) {
if($name == 'code') {
$name = basename($file, '.php');
}
$directory = OUT_DIR . $type;
if ( ! is_dir($directory)) {
if( ! mkdir($directory, 0777, true)) {
print "Couldn't make: $directory\n";
continue;
}
}
$file = $directory . '/'. $name . '.php';
if( ! is_file($file)) {
$block = "<?php\n" . $block;
}
file_put_contents($file, $block . "\n\n", FILE_APPEND);
}
}
// Reset blocks
$nodeVisitor->blocks = array();
$nodeVisitor->inside_block = false;
//echo $code;
} catch (PhpParser\Error $e) {
echo 'Parse Error: ', $e->getMessage();
}
}
/*
arsort($nodeVisitor->functions['static']);
arsort($nodeVisitor->functions['dynamic']);
print_r($nodeVisitor->functions);
*/
print "Done\n";
<?php
return array(
// Example facade replacement
//'get_option' => 'MyClass::get_option'
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment