Skip to content

Instantly share code, notes, and snippets.

@gwijayas
Last active August 29, 2015 14:24
Show Gist options
  • Save gwijayas/6d918809f11936b0e704 to your computer and use it in GitHub Desktop.
Save gwijayas/6d918809f11936b0e704 to your computer and use it in GitHub Desktop.
<?php
/**
* This script can be used for generating PHP model for PDT.
* It builds PHP functions according to the loaded extensions in running PHP,
* using complementary information gathered from PHP.net documentation
*
* @author Michael Spector <[email protected]>
*/
if (version_compare(phpversion(), "5.0.0") < 0) {
die ("This script requires PHP 5.0.0 or higher!\n");
}
$splitFiles = true;
$phpdocDir = null;
preg_match('/^[^.]+\.[^.]+/', phpversion(), $matches);
echo "PHP version: {$matches[0]}\n";
$phpDir = "php".$matches[0];
// Parse arguments:
$argv = $_SERVER["argv"];
$argv0 = array_shift ($argv);
for ($i = 0; $i < count($argv); ++$i) {
switch ($argv[$i]) {
case "-nosplit":
$splitFiles = false;
break;
case "-help":
show_help();
break;
default:
$phpdocDir = $argv[$i];
}
}
if (!$phpdocDir) {
show_help();
}
$functionsDoc = parse_phpdoc_functions ($phpdocDir);
$classesDoc = parse_phpdoc_classes ($phpdocDir);
$constantsDoc = parse_phpdoc_constants ($phpdocDir);
$processedFunctions = array();
$processedClasses = array();
$processedConstants = array();
@mkdir ($phpDir);
if (!$splitFiles) {
begin_file_output();
}
$extensions = get_loaded_extensions();
foreach ($extensions as $extName) {
if ($splitFiles) {
begin_file_output();
}
print_extension (new ReflectionExtension ($extName));
if ($splitFiles) {
finish_file_output("{$phpDir}/{$extName}.php");
}
}
if ($splitFiles) {
begin_file_output();
}
$intFunctions = get_defined_functions();
foreach ($intFunctions["internal"] as $intFunction) {
if (!@$processedFunctions[strtolower($intFunction)]) {
print_function (new ReflectionFunction ($intFunction));
}
}
$intClasses = array_merge (get_declared_classes(), get_declared_interfaces());
foreach ($intClasses as $intClass) {
if (!@$processedClasses[strtolower($intClass)]) {
print_class (new ReflectionClass ($intClass));
}
}
print "\n";
$constants = get_defined_constants(true);
$intConstants = @$constants["internal"];
// add magic constants:
$intConstants['__FILE__'] = null;
$intConstants['__LINE__'] = null;
$intConstants['__CLASS__'] = null;
$intConstants['__FUNCTION__'] = null;
$intConstants['__METHOD__'] = null;
if (version_compare(phpversion(), "5.3.0") >= 0) {
$intConstants['__DIR__'] = null;
$intConstants['__NAMESPACE__'] = null;
}
foreach ($intConstants as $name => $value) {
if (!@$processedConstants[$name]) {
print_constant ($name, $value);
}
}
finish_file_output("{$phpDir}/basic.php");
// Create .list file
$fp = fopen ("{$phpDir}/.list", "w");
foreach (glob("{$phpDir}/*.php") as $f) {
fwrite ($fp, basename($f));
fwrite ($fp, "\n");
}
fclose($fp);
echo 'Finished...';
// === Functions ===
/**
* Makes generic key from given function name
* @param name string Function name
* @return string generic key
*/
function make_funckey_from_str ($name) {
$name = str_replace ("->", "::", $name);
$name = str_replace ("()", "", $name);
$name = strtolower ($name);
return $name;
}
/**
* Replaces all invalid charaters with '_' in PHP identifier
* @param name PHP identifier
* @return string PHP identifier with stripped invalid characters
*/
function clean_php_identifier ($name) {
$name = preg_replace('/[^\$\w\_]+/', '_', $name);
return $name;
}
/**
* Makes generic key from given function reference
* @param name ReflectionMethod function reference
* @return string generic key
*/
function make_funckey_from_ref ($ref) {
if ($ref instanceof ReflectionMethod) {
$funckey = strtolower($ref->getDeclaringClass()->getName())."::".strtolower($ref->getName());
} else {
$funckey = strtolower($ref->getName());
}
return $funckey;
}
/**
* Parses PHP documentation
* @param phpdocDir string PHP.net documentation directory
* @return array Function information gathered from the PHP.net documentation by parsing XML files
*/
function parse_phpdoc_functions ($phpdocDir) {
$xml_files = array_merge (
glob ("{$phpdocDir}/reference/*/*/*.xml")
);
$functionsDoc = array();
foreach ($xml_files as $xml_file) {
$xml = load_xml ($xml_file);
if (preg_match ('@<refentry.*?xml:id=["\'](.*?)["\'].*?>.*?<refname>(.*?)</refname>.*?<refpurpose>(.*?)</refpurpose>@s', $xml, $match)) {
$refname = make_funckey_from_str ($match[2]);
$functionsDoc[$refname]['id'] = $match[1];
$functionsDoc[$refname]['quickref'] = trim($match[3]);
if (preg_match ('@<refsect1\s+role=["\']description["\']>(.*?)</refsect1>@s', $xml, $match)) {
$description = $match[1];
$function_alias = null;
$parameters = null;
$has_object_style = false;
if (preg_match ('@^(.*?)<classsynopsis>.*?<classname>(.*)</classname>.*?<methodsynopsis>.*?<type>(.*?)</type>.*?<methodname>(.*?)</methodname>(.*?)</methodsynopsis>.*?</classsynopsis>(.*)$@s', $description, $match)) {
$functionsDoc[$refname]['classname'] = trim($match[2]);
$functionsDoc[$refname]['returntype'] = trim($match[3]);
$functionsDoc[$refname]['methodname'] = trim($match[4]);
$parameters = $match[5];
$description = $match[1].$match[6];
$has_object_style = true;
}
if (preg_match ('@^(.*?)<classsynopsis>.*?<classname>(.*)</classname>.*?<constructorsynopsis>.*?<methodname>(.*?)</methodname>(.*?)</constructorsynopsis>.*?</classsynopsis>(.*)$@s', $description, $match)) {
$functionsDoc[$refname]['classname'] = trim($match[2]);
$functionsDoc[$refname]['methodname'] = trim($match[3]);
$parameters = $match[4];
$description = $match[1].$match[5];
$has_object_style = true;
}
if (preg_match ('@<methodsynopsis>.*?<type>(.*?)</type>.*?<methodname>(.*?)</methodname>(.*?)</methodsynopsis>@s', $description, $match)) {
if ($has_object_style) {
$function_alias = trim($match[2]);
} else {
//For return type of simplexml_load_string and simplexml_load_file.
if(preg_match ('@<refsect1\s+role=["\']returnvalues["\']>(.*?)</refsect1>@s', $xml, $match1)){
$returnvalues = $match1[1];
if(preg_match ('@<type>object</type> of class <type>(.*?)</type>@s', $returnvalues, $match1)){
$functionsDoc[$refname]['returntype'] = trim($match1[1]);
}else{
$functionsDoc[$refname]['returntype'] = trim($match[1]);
}
}
else{
$functionsDoc[$refname]['returntype'] = trim($match[1]);
}
$functionsDoc[$refname]['methodname'] = trim($match[2]);
$parameters = $match[3];
}
}
if ($parameters) {
if (preg_match_all ('@<methodparam\s*(.*?)>.*?<type>(.*?)</type>.*?<parameter\s*(.*?)>(.*?)</parameter>.*?</methodparam>@s', $parameters, $match)) {
for ($i = 0; $i < count($match[0]); ++$i) {
$parameter = array (
'type' => trim($match[2][$i]),
'name' => clean_php_identifier(trim($match[4][$i])),
);
if (preg_match ('@choice=[\'"]opt[\'"]@', $match[1][$i])) {
$parameter['isoptional'] = true;
}
if (preg_match ('@role=[\'"]reference[\'"]@', $match[3][$i])) {
$parameter['isreference'] = true;
}
$functionsDoc[$refname]['parameters'][] = $parameter;
}
}
}
}
if (preg_match ('@<refsect1\s+role=["\']parameters["\']>(.*?)</refsect1>@s', $xml, $match)) {
$parameters = $match[1];
if (preg_match_all('@<varlistentry\s*.*?>.*?<parameter>(.*?)</parameter>.*?<listitem\s*.*?>(.*?)</listitem>.*?</varlistentry>@s', $parameters, $match)) {
for ($i = 0; $i < count($match[0]); $i++) {
for ($j = 0; $j < count(@$functionsDoc[$refname]['parameters']); $j++) {
if ($match[1][$i] == $functionsDoc[$refname]['parameters'][$j]['name']) {
$functionsDoc[$refname]['parameters'][$j]['paramdoc'] = xml_to_phpdoc ($match[2][$i]);
break;
}
}
}
}
}
if (preg_match ('@<refsect1\s+role=["\']returnvalues["\']>(.*?)</refsect1>@s', $xml, $match)) {
$returnvalues = $match[1];
if (preg_match ('@<para>\s*(Returns)?(.*)</para>?@s', $returnvalues, $match)) {
$functionsDoc[$refname]['returndoc'] = xml_to_phpdoc ($match[2]);
}
}
if (preg_match ('@&warn\.deprecated.func-(.*?);@s', $xml, $match)) {
$deprecatedSince = $match[1];
$functionsDoc[$refname]['deprecated'] = 'Since ' . str_replace('-', '.',$deprecatedSince);
}
// Create information for function alias
if ($function_alias) {
$functionsDoc[$function_alias] = $functionsDoc[$refname];
}
}
}
return $functionsDoc;
}
/**
* Parses PHP documentation
* @param phpdocDir string PHP.net documentation directory
* @return array Class information gathered from the PHP.net documentation by parsing XML files
*/
function parse_phpdoc_classes ($phpdocDir) {
$classesDoc = array();
$xml_files = array_merge (
glob ("{$phpdocDir}/reference/*/reference
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment