php/sigfiles/generate.php
author Tomas Mysik <tmysik@netbeans.org>
Thu, 08 Jun 2017 06:53:53 +0200
changeset 6389 8b57d477a2db
parent 6388 d493d11c1b46
child 6390 73661dbdafd6
permissions -rw-r--r--
Fix some incorrectly generated abstract classes
     1 <?php
     2 /**
     3  * This script can be used for generating PHP model for PDT.
     4  * It builds PHP functions according to the loaded extensions in running PHP,
     5  * using complementary information gathered from PHP.net documentation
     6  *
     7  * @author Michael Spector <michael@zend.com>
     8  */
     9 
    10 define("BRANCH_DIR", ""); // can be e.g. "/trunk" (do not forget slash!)
    11 define("DOC_URL", "./html/");      // PHP documentation, separate HTML files
    12 if (!is_dir(DOC_URL)) {
    13     die('Incorrect directory for separated HTML files ("./html/" expected)!');
    14 }
    15 
    16 if (version_compare(phpversion(), "5.0.0") < 0) {
    17 	die ("This script requires PHP 5.0.0 or higher!\n");
    18 }
    19 
    20 $splitFiles = true;
    21 $phpdocDir = null;
    22 
    23 $phpDir = "php";
    24 $lang = "en";
    25 
    26 // Parse arguments:
    27 $argv = $_SERVER["argv"];
    28 $argv0 = array_shift ($argv);
    29 for ($i = 0; $i < count($argv); ++$i) {
    30 	switch ($argv[$i]) {
    31 		case "-nosplit":
    32 			$splitFiles = false;
    33 			break;
    34 
    35 		case "-split":
    36 			$splitFiles = true;
    37 			break;
    38 
    39 		case "-help":
    40 			show_help();
    41 			break;
    42 
    43 		case "-lang":
    44 			++$i;
    45 			$lang = $argv[$i];
    46                         if ($lang[0] === '-') {
    47 				show_message("Invalid arg for -lang: " . $argv[$i]);
    48 				show_help();
    49                         }
    50 			break;
    51 
    52 		case "-output":
    53 			++$i;
    54 			$phpDir = $argv[$i];
    55                         if ($phpDir[0] === '-') {
    56 				show_message("Invalid arg for -output: " . $argv[$i]);
    57 				show_help();
    58                         }
    59 			break;
    60 
    61 		default:
    62 			$phpdocDir = $argv[$i];
    63 	}
    64 }
    65 
    66 if (!$phpdocDir) {
    67 	show_help();
    68 }
    69 
    70 /***************** REMOVED FUNCTIONS (START) *************************/
    71 
    72 // add these functions to $removedFunctions!
    73 
    74 if (!function_exists('ob_iconv_handler')) {
    75     function ob_iconv_handler($contents, $status) {}
    76 }
    77 if (!function_exists('ob_tidyhandler')) {
    78     function ob_tidyhandler($input, $mode = 0) {}
    79 }
    80 if (!function_exists('session_register')) {
    81     function session_register($name, $_ = null) {}
    82 }
    83 if (!function_exists('session_unregister')) {
    84     function session_unregister($name) {}
    85 }
    86 if (!function_exists('session_is_registered')) {
    87     function session_is_registered($name) {}
    88 }
    89 if (!function_exists('chroot')) {
    90     function chroot($directory) {}
    91 }
    92 
    93 /***************** REMOVED FUNCTIONS (END) *************************/
    94 
    95 $entities = parse_entities($phpdocDir, $lang);
    96 $extensions = get_loaded_extensions();
    97 $functionsDoc = parse_phpdoc_functions ($phpdocDir, $extensions, $lang);
    98 $fieldsDoc = parse_phpdoc_fields ($phpdocDir, $extensions, $lang);
    99 $classesDoc = parse_phpdoc_classes ($phpdocDir, $extensions, $lang);
   100 $constantsDoc = parse_phpdoc_constants ($phpdocDir);
   101 $removedFunctions = array(
   102     'ob_iconv_handler',
   103     'ob_tidyhandler',
   104     'session_register',
   105     'session_unregister',
   106     'session_is_registered',
   107     'chroot',
   108 );
   109 $functionBlackList = array(
   110     'oci_lob_save' => 1,
   111     'oci_lob_import' => 1,
   112     'oci_lob_size' => 1,
   113     'oci_lob_load' => 1,
   114     'oci_lob_read' => 1,
   115     'oci_lob_eof' => 1,
   116     'oci_lob_tell' => 1,
   117     'oci_lob_truncate' => 1,
   118     'oci_lob_erase' => 1,
   119     'oci_lob_flush' => 1,
   120     'ocisetbufferinglob' => 1,
   121     'ocigetbufferinglob' => 1,
   122     'oci_lob_rewind' => 1,
   123     'oci_lob_write' => 1,
   124     'oci_lob_append' => 1,
   125     'oci_lob_export' => 1,
   126     'oci_lob_seek' => 1,
   127     'oci_free_collection' => 1,
   128     'oci_collection_append' => 1,
   129     'oci_collection_element_get' => 1,
   130     'oci_collection_element_assign' => 1,
   131     'oci_collection_size' => 1,
   132     'oci_collection_max' => 1,
   133     'oci_collection_trim' => 1,
   134     'oci_collection_assign' => 1,
   135 );
   136 $methodBlackList = array(
   137     'clone',
   138     'throw',
   139     'isset',
   140     'echo',
   141     'eval',
   142 );
   143 $preferHtmlProperties = array(
   144     'mysqli',
   145 );
   146 
   147 $processedFunctions = $functionBlackList;
   148 $processedClasses = array();
   149 $processedConstants = array();
   150 
   151 @mkdir ($phpDir);
   152 
   153 if (!$splitFiles) {
   154 	begin_file_output();
   155 }
   156 foreach ($extensions as $extName) {
   157 	if ($splitFiles) {
   158 		begin_file_output();
   159 	}
   160 	print_extension (new ReflectionExtension ($extName));
   161 	if ($splitFiles) {
   162 		finish_file_output("{$phpDir}/{$extName}.php");
   163 	}
   164 }
   165 
   166 if ($splitFiles) {
   167 	begin_file_output();
   168 }
   169 $intFunctions = get_defined_functions();
   170 foreach ($intFunctions["internal"] as $intFunction) {
   171 	if (!@$processedFunctions[strtolower($intFunction)]) {
   172 		print_function (new ReflectionFunction ($intFunction));
   173 	}
   174 }
   175 
   176 $intClasses = array_merge (get_declared_classes(), get_declared_interfaces(), get_declared_traits());
   177 foreach ($intClasses as $intClass) {
   178     if (strpos($intClass, 'NetBeans_') === 0) {
   179         continue;
   180     }
   181 	if (!@$processedClasses[strtolower($intClass)]) {
   182 		print_class (new ReflectionClass ($intClass));
   183 	}
   184 }
   185 
   186 print "\n";
   187 $constants = get_defined_constants(true);
   188 $intConstants = isset($constants["internal"]) ? $constants["internal"] : array();
   189 // add magic constants:
   190 $intConstants['__FILE__'] = null;
   191 $intConstants['__LINE__'] = null;
   192 $intConstants['__CLASS__'] = null;
   193 $intConstants['__FUNCTION__'] = null;
   194 $intConstants['__METHOD__'] = null;
   195 $intConstants['__TRAIT__'] = null;
   196 if (version_compare(phpversion(), "5.3.0") >= 0) {
   197 	$intConstants['__DIR__'] = null;
   198 	$intConstants['__NAMESPACE__'] = null;
   199 }
   200 foreach ($intConstants as $name => $value) {
   201 	if (!@$processedConstants[$name]) {
   202 		print_constant ($name, $value);
   203 	}
   204 }
   205 
   206 finish_file_output("{$phpDir}/basic.php");
   207 
   208 // removed functions
   209 if ($splitFiles) {
   210     begin_file_output();
   211 }
   212 foreach ($removedFunctions as $removedFunction) {
   213 	if (!@$processedFunctions[strtolower($removedFunction)]) {
   214 		print_function (new ReflectionFunction ($removedFunction));
   215 	}
   216 }
   217 if ($splitFiles) {
   218     finish_file_output("{$phpDir}/removed.php");
   219 }
   220 
   221 
   222 // Create .list file
   223 $fp = fopen ("{$phpDir}/.list", "w");
   224 foreach (glob("{$phpDir}/*.php") as $f) {
   225 	fwrite ($fp, basename($f));
   226 	fwrite ($fp, "\n");
   227 }
   228 fclose($fp);
   229 
   230 
   231 function findVerInfo($file)
   232  {
   233     $url = DOC_URL.$file.".html";
   234     $search_for = '<p class="verinfo">';
   235     //echo "Reading $url :\n";
   236 
   237     if (!is_file($url)) {
   238         return;
   239     }
   240 
   241     $file_contents = file_get_contents($url);
   242 
   243     $start_pos = strpos($file_contents, $search_for);
   244 
   245     if ($start_pos !== 0) {
   246        $start_pos += strlen($search_for);
   247        $end_pos = strpos($file_contents, '</p>', $start_pos);
   248 
   249        if ($end_pos !== 0) {
   250           $verinfo = substr($file_contents, $start_pos, $end_pos - $start_pos);
   251           //echo "Ver. info: $verinfo\n";
   252           return $verinfo;
   253        }
   254     }
   255  }
   256 
   257 // === Functions ===
   258 /**
   259  * Makes generic key from given function name
   260  * @param name string Function name
   261  * @return string generic key
   262  */
   263 function make_funckey_from_str ($name) {
   264 	$name = str_replace ("->", "::", $name);
   265 	$name = str_replace ("()", "", $name);
   266 	$name = strtolower ($name);
   267 	return $name;
   268 }
   269 
   270 /**
   271  * Replaces all invalid charaters with '_' in PHP identifier
   272  * @param name PHP identifier
   273  * @return string PHP identifier with stripped invalid characters
   274  */
   275 function clean_php_identifier ($name) {
   276 	$name = preg_replace('/[^\$\w\_]+/', '_', $name);
   277 	return $name;
   278 }
   279 
   280 function clean_php_value($type) {
   281     $type = trim($type);
   282     $type = str_replace("&null;", "null", $type);
   283     $type = str_replace("&true;", "true", $type);
   284     $type = str_replace("&false;", "false", $type);
   285     $type = str_replace("&quot;", "", $type);
   286     $type = strip_tags($type);
   287     return $type;
   288 }
   289 
   290 /**
   291  * Makes generic key from given function reference
   292  * @param name ReflectionMethod function reference
   293  * @return string generic key
   294  */
   295 function make_funckey_from_ref ($ref) {
   296 	if ($ref instanceof ReflectionMethod) {
   297 		$funckey = make_classmember_ref($ref->getDeclaringClass()->getName(), $ref->getName());
   298 	} else {
   299 		$funckey = strtolower($ref->getName());
   300 	}
   301 	return $funckey;
   302 }
   303 function make_property_from_ref ($ref) {
   304 	if ($ref instanceof ReflectionProperty) {
   305 		$funckey = make_classmember_ref($ref->getDeclaringClass()->getName(), $ref->getName());
   306 	} else {
   307 		throw new Exception("Unexpected type: ".gettype($ref));
   308 	}
   309 	return $funckey;
   310 }
   311 
   312 function make_classmember_ref ($className, $memberName) {
   313 	return strtolower($className)."::".strtolower($memberName);
   314 }
   315 
   316 
   317 /**
   318  * Parses PHP documentation
   319  * @param phpdocDir string PHP.net documentation directory
   320  * @return array Function information gathered from the PHP.net documentation by parsing XML files
   321  */
   322 function parse_phpdoc_functions ($phpdocDir, $extensions, $lang) {
   323 	$xml_files = array_merge (
   324 		glob ("{$phpdocDir}/{$lang}" . BRANCH_DIR . "/reference/*/functions/*.xml"),
   325 		glob ("{$phpdocDir}/{$lang}" . BRANCH_DIR . "/language/predefined/*/*.xml"),
   326 		glob ("{$phpdocDir}/{$lang}" . BRANCH_DIR . "/reference/*/functions/*/*.xml")
   327 	);
   328 	foreach ($extensions as $extName) {
   329 		$extName = strtolower($extName);
   330 		$globPattern = "{$phpdocDir}/{$lang}" . BRANCH_DIR . "/reference/{$extName}/*/*.xml";
   331 		$xml_files = array_merge (
   332 			$xml_files,
   333 			glob ($globPattern)
   334 		);
   335 	}
   336     $functionsDoc = array();
   337 	foreach ($xml_files as $xml_file) {
   338 		$xml = file_get_contents ($xml_file);
   339 
   340 		if (preg_match ('@<refentry.*?xml:id=["\'](.*?)["\'].*?>.*?<refname>(.*?)</refname>\s*(?:<refname>(.*?)</refname>)?.*?<refpurpose>(.*?)</refpurpose>@s', $xml, $match)) {
   341             $id = $match[1];
   342             $refnames = array($match[2], $match[3]);
   343             $phpdoc = $match[4];
   344             foreach ($refnames as $refname) {
   345                 $refname = trim($refname);
   346                 if ($refname == '') {
   347                     continue;
   348                 }
   349                 $refname = make_funckey_from_str ($refname);
   350                 if (array_key_exists($refname, $functionsDoc)) {
   351                     // already there
   352                     continue;
   353                 }
   354                 $functionsDoc[$refname] = array();
   355                 $functionsDoc[$refname]['id'] = $id;
   356                 $functionsDoc[$refname]['quickref'] = xml_to_phpdoc($phpdoc);
   357                 $functionsDoc[$refname]['deprecated'] = strpos($xml_file, "/oldaliases/") !== false;
   358 
   359                 if (preg_match ('@<refsect1\s+role=["\']description["\']>(.*?)</refsect1>@s', $xml, $match)) {
   360                     $description = $match[1];
   361                     $function_alias = null;
   362                     $parameters = null;
   363                     $has_object_style = false;
   364                     if (preg_match ('@^(.*?)<classsynopsis>.*?<classname>(.*)</classname>.*?<methodsynopsis>.*?<type>(.*?)</type>.*?<methodname>(.*?)</methodname>(.*?)</methodsynopsis>.*?</classsynopsis>(.*)$@s', $description, $match)) {
   365                         $functionsDoc[$refname]['classname'] = trim($match[2]);
   366                         $functionsDoc[$refname]['returntype'] = trim($match[3]);
   367                         $functionsDoc[$refname]['methodname'] = trim($match[4]);
   368                         $parameters = $match[5];
   369                         $description = $match[1].$match[6];
   370                         $has_object_style = true;
   371                     }
   372                     $methodsynopsis = null;
   373                     if ($refname == 'number_format') {
   374                         $methodsynopsis = preg_match_all ('@<methodsynopsis>.*?<type>(.*?)</type>.*?<methodname>(.*?)</methodname>(.*?)</methodsynopsis>@s', $description, $tmp);
   375                         $match = array();
   376                         foreach ($tmp as $key => $val) {
   377                             $match[$key] = $val[count($val) - 1];
   378                         }
   379                     } else {
   380                         if (strpos($refname, '::') !== false) {
   381                             $methodsynopsis = preg_match ('@<methodsynopsis role="oop">.*?(?:<type>(.*?)</type>.*?)?<methodname>(.*?)</methodname>(.*?)</methodsynopsis>@s', $description, $match);
   382                         }
   383                         if (!$methodsynopsis) {
   384                             $methodsynopsis = preg_match ('@<methodsynopsis>.*?(?:<type>(.*?)</type>.*?)?<methodname>(.*?)</methodname>(.*?)</methodsynopsis>@s', $description, $match);
   385                         }
   386                         if (!$methodsynopsis) {
   387                             $methodsynopsis = preg_match ('@<constructorsynopsis>.*?(?:<type>(.*?)</type>.*?)?<methodname>(.*?)</methodname>(.*?)</constructorsynopsis>@s', $description, $match);
   388                         }
   389                     }
   390                     if ($methodsynopsis) {
   391                         if ($has_object_style && make_funckey_from_str($match[2]) != $refname) {
   392                             $function_alias = trim($match[2]);
   393                         } else {
   394                             $functionsDoc[$refname]['returntype'] = trim(str_replace('-', '_', $match[1])); // e.g. OCI-Collection -> OCI_Collection
   395                             $functionsDoc[$refname]['methodname'] = trim($match[2]);
   396                                                     $parameters = $match[3];
   397                         }
   398                     }
   399                     if ($parameters) {
   400                         if (preg_match_all ('@<methodparam\s*(.*?)>.*?<type>(.*?)</type>.*?<parameter\s*(.*?)>(.*?)</parameter>(?:<initializer>(.+?)</initializer>)?.*?</methodparam>@s', $parameters, $match)) {
   401                             for ($i = 0; $i < count($match[0]); ++$i) {
   402                                 $parameter = array (
   403                                     'type' => trim(str_replace('-', '_', $match[2][$i])), // e.g. OCI-Collection -> OCI_Collection
   404                                     'name' => clean_php_identifier(trim($match[4][$i])),
   405                                 );
   406                                 if (preg_match ('@choice=[\'"]opt[\'"]@', $match[1][$i])) {
   407                                     $parameter['isoptional'] = true;
   408                                 }
   409                                 if (preg_match ('@role=[\'"]reference[\'"]@', $match[3][$i])) {
   410                                     $parameter['isreference'] = true;
   411                                 }
   412                                 if (@strlen(trim($match[5][$i]))) {
   413                                     $def = $match[5][$i];
   414                                     if ($def == '"\"') {
   415                                         $def = '"\\\\"';
   416                                     }
   417                                     $parameter['defaultvalue'] = clean_php_value($def);
   418                                                                     $parameter['isoptional'] = true;
   419                                 }
   420                                 $functionsDoc[$refname]['parameters'][] = $parameter;
   421                             }
   422                         }
   423                     }
   424                 }
   425                 if (preg_match ('@<refsect1\s+role=["\']parameters["\']>(.*?)</refsect1>@s', $xml, $match)) {
   426                     $parameters = $match[1];
   427                     if (preg_match_all('@<varlistentry\s*.*?>.*?<parameter>(.*?)</parameter>.*?<listitem\s*.*?>(.*?)</listitem>.*?</varlistentry>@s', $parameters, $match)) {
   428                         for ($i = 0; $i < count($match[0]); $i++) {
   429                             for ($j = 0; $j < count(@$functionsDoc[$refname]['parameters']); $j++) {
   430                                 if (clean_php_identifier(trim($match[1][$i])) == $functionsDoc[$refname]['parameters'][$j]['name']) {
   431                                     $functionsDoc[$refname]['parameters'][$j]['paramdoc'] = xml_to_phpdoc ($match[2][$i]);
   432                                     break;
   433                                 }
   434                             }
   435                         }
   436                     }
   437                 }
   438                 if (preg_match ('@<refsect1\s+role=["\']returnvalues["\']>(.*?)</refsect1>@s', $xml, $match)) {
   439                     $returnvalues = $match[1];
   440                     if (preg_match ('@<para>\s*(.*)</para>?@s', $returnvalues, $match)) {
   441                         $functionsDoc[$refname]['returndoc'] = preg_replace("@^Returns @", "", xml_to_phpdoc ($match[1]));
   442                     }
   443                 }
   444 
   445                 // Create information for function alias
   446                 if ($function_alias) {
   447                     $functionsDoc[$function_alias] = $functionsDoc[$refname];
   448                 }
   449             }
   450 		}
   451 	}
   452 	return $functionsDoc;
   453 }
   454 
   455 /**
   456  * Parses PHP documentation
   457  * @param phpdocDir string PHP.net documentation directory
   458  * @return array Function information gathered from the PHP.net documentation by parsing XML files
   459  */
   460 function parse_phpdoc_fields ($phpdocDir, $extensions, $lang) {
   461 	$xml_files = array();
   462 	foreach ($extensions as $extName) {
   463 		$extName = strtolower($extName);
   464 
   465 		$xml_files = array_merge (
   466 			$xml_files,
   467 			glob ("{$phpdocDir}/{$lang}" . BRANCH_DIR . "/reference/{$extName}/*.xml"),
   468                         glob ("{$phpdocDir}/{$lang}" . BRANCH_DIR . "/reference/{$extName}/*/*.xml")
   469 		);
   470 	}
   471         foreach ($xml_files as $xml_file) {
   472             $xml = file_get_contents($xml_file);
   473             if (preg_match('@<classsynopsisinfo>.*?<classname>(.*)</classname>.*?</classsynopsisinfo>@s', $xml, $matchOffset, PREG_OFFSET_CAPTURE)) {
   474                 $classname = $matchOffset[1][0];
   475                 if (preg_match_all("@<fieldsynopsis>.*?<type>(.*?)</type>.*?<varname.*?>(.*?)</varname>@s", $xml, $matchOffset,null,$matchOffset[1][1])) {
   476                     for ($index = 0; $index < count($matchOffset[2]); $index++) {
   477                         $name = $matchOffset[2][$index];
   478                         $type= $matchOffset[1][$index];
   479                         $exploded = explode("::", $name);
   480                         if (count($exploded) > 1) {
   481                             $name = $exploded[1];
   482                         }
   483                         $reference = make_classmember_ref($classname, $name);
   484                         $fieldsDoc[$reference]['field'] = $name;
   485                         $fieldsDoc[$reference]['type'] = $type;
   486                     }
   487                 }
   488             } else {
   489                 if (preg_match('@<classsynopsis>.*?<classname>(.*)</classname>.*?<fieldsynopsis>.*?<type>(.*?)</type>.*?<varname.*?>(.*?)</varname>.*?</classsynopsis>@s', $xml, $match)) {
   490                     $reference = make_classmember_ref($match[1], $match[3]);
   491                     $fieldsDoc[$reference]['field'] = $match[3];
   492                     $fieldsDoc[$reference]['type'] = $match[2];
   493                     //$fieldsDoc[$refname]['quickref'] = trim($match[3]);
   494                 }
   495             }
   496 
   497         }
   498         if (isset($fieldsDoc)) {
   499             return $fieldsDoc;
   500         }
   501         return array();
   502 }
   503 
   504 /**
   505  * Parses PHP documentation
   506  * @param phpdocDir string PHP.net documentation directory
   507  * @return array Class information gathered from the PHP.net documentation by parsing XML files
   508  */
   509 function parse_phpdoc_classes ($phpdocDir, $extensions, $lang) {
   510 	$xml_files = array_merge (
   511 		glob ("{$phpdocDir}/{$lang}" . BRANCH_DIR . "/reference/*/reference.xml"),
   512 		glob ("{$phpdocDir}/{$lang}" . BRANCH_DIR . "/reference/*/classes.xml"),
   513 		glob ("{$phpdocDir}/{$lang}" . BRANCH_DIR . "/language/*/*.xml"),
   514 		glob ("{$phpdocDir}/{$lang}" . BRANCH_DIR . "/language/*.xml")
   515 	);
   516 	foreach ($extensions as $extName) {
   517 		$extName = strtolower($extName);
   518 		$globPattern = "{$phpdocDir}/{$lang}" . BRANCH_DIR . "/reference/{$extName}/*.xml";
   519 		$xml_files = array_merge (
   520 			$xml_files,
   521 			glob ($globPattern)
   522 		);
   523 	}
   524 
   525     $classesDoc = array();
   526 	foreach ($xml_files as $xml_file) {
   527 		$xml = file_get_contents ($xml_file);
   528 		if (preg_match ('@xml:id=["\'](.*?)["\']@', $xml, $match)) {
   529 			$id = $match[1];
   530 			$prefixId = substr($id, 0, strlen("class."));
   531 			$clsNamePattern = ($prefixId === "class.") ?
   532 			'@<ooclass><classname>(.*?)</classname></ooclass>@' :
   533 			'@<title><classname>(.*?)</classname></title>@';
   534 			if (preg_match_all ($clsNamePattern, $xml, $match)) {
   535 				for ($i = 0; $i < count($match[0]); ++$i) {
   536 					$class = $match[1][$i];
   537 					$refname = strtolower ($class);
   538 					$classesDoc[$refname]['id'] = $id;
   539 					$classesDoc[$refname]['name'] = $class;
   540 					$offsetPattern = ($prefixId === "class.") ?
   541 						"@xml:id=[\"'](.*?)\.intro[\"']@i" :
   542 						"@<title><classname>{$class}</classname></title>@";
   543 					if (preg_match ($offsetPattern , $xml, $matchOffset,PREG_OFFSET_CAPTURE)) {
   544 						$docPattern = '@<para>(.*?)</para>@s';
   545 						if (preg_match ($docPattern, $xml, $match2,null,$matchOffset[0][1])) {
   546 							$doc = xml_to_phpdoc($match2[1]);
   547 							$classesDoc[$refname]['doc'] = $doc;
   548 						}
   549 					}
   550 				}
   551 			}
   552 		}
   553 	}
   554 	return $classesDoc;
   555 }
   556 
   557 /**
   558  * Parses PHP documentation
   559  * @param phpdocDir string PHP.net documentation directory
   560  * @return array Constant information gathered from the PHP.net documentation by parsing XML files
   561  */
   562 function parse_phpdoc_constants ($phpdocDir) {
   563 	exec ("find ".addslashes($phpdocDir)." -name \"*constants.xml\"", $xml_files);
   564 	foreach ($xml_files as $xml_file) {
   565 		$xml = file_get_contents ($xml_file);
   566 
   567 		if (preg_match ('@xml:id=["\'](.*?)["\']@', $xml, $match)) {
   568 			$id = $match[1];
   569 			if (preg_match_all ('@<term>\s*<constant>([a-zA-Z_:][a-zA-Z0-9_:]*)</constant>.*?</term>.*?<listitem>(.*?)</listitem>@s', $xml, $match)) {
   570 				for ($i = 0; $i < count($match[0]); ++$i) {
   571 					$constant = $match[1][$i];
   572 					$constantsDoc[$constant]['id'] = $id;
   573 					$constantsDoc[$constant]['doc'] = xml_to_phpdoc($match[2][$i]);
   574 				}
   575 			}
   576 			if (preg_match_all (
   577 				'@<entry>\s*<constant>([a-zA-Z_][a-zA-Z0-9_]*)</constant>.*?</entry>\s*<entry>\d+</entry>\s*<entry>(.*?)</entry>@s', $xml, $match)
   578 				|| preg_match_all ('@<entry>\s*<constant>([a-zA-Z_][a-zA-Z0-9_]*)</constant>.*?</entry>\s*<entry>(.*?)</entry>@s', $xml, $match)) {
   579 
   580 				for ($i = 0; $i < count($match[0]); ++$i) {
   581 					$constant = $match[1][$i];
   582 					$constantsDoc[$constant]['id'] = $id;
   583 					$constantsDoc[$constant]['doc'] = xml_to_phpdoc($match[2][$i]);
   584 				}
   585 			}
   586 		}
   587 	}
   588 	return $constantsDoc;
   589 }
   590 
   591 /**
   592  * Prints ReflectionExtension in format of PHP code
   593  * @param extRef ReflectionExtension object
   594  */
   595 function print_extension ($extRef) {
   596     global $functionBlackList;
   597 
   598 	print "\n// Start of {$extRef->getName()} v.{$extRef->getVersion()}\n";
   599 
   600 	// process classes:
   601 	$classesRef = $extRef->getClasses();
   602 	if (count ($classesRef) > 0) {
   603 		foreach ($classesRef as $classRef) {
   604 			print_class ($classRef);
   605 		}
   606 	}
   607 
   608 	// process functions
   609 	$funcsRef = $extRef->getFunctions();
   610 	if (count ($funcsRef) > 0) {
   611 		foreach ($funcsRef as $funcName => $funcRef) {
   612                     if (array_key_exists($funcName, $functionBlackList)) {
   613                         continue;
   614                     }
   615 			print_function ($funcRef);
   616 		}
   617 		print "\n";
   618 	}
   619 
   620 	// process constants
   621 	$constsRef = $extRef->getConstants();
   622 	if (count ($constsRef) > 0) {
   623 		print_constants ($constsRef);
   624 		print "\n";
   625 	}
   626 
   627 	print "// End of {$extRef->getName()} v.{$extRef->getVersion()}\n";
   628 }
   629 
   630 /**
   631  * Prints ReflectionClass in format of PHP code
   632  * @param classRef ReflectionClass object
   633  * @param tabs integer[optional] number of tabs for indentation
   634  */
   635 function print_class (ReflectionClass $classRef, $tabs = 0) {
   636 	global $processedClasses, $preferHtmlProperties, $methodBlackList;
   637 	$processedClasses [strtolower($classRef->getName())] = true;
   638 
   639 	print "\n";
   640 	print_doccomment ($classRef, $tabs);
   641 	print_tabs ($tabs);
   642 	if ($classRef->isFinal()) print "final ";
   643 
   644         if ($classRef->isInterface()) {
   645             print "interface ";
   646         } elseif ($classRef->isTrait()) {
   647             print "trait ";
   648         } else {
   649             if ($classRef->isAbstract()) {
   650                 print "abstract ";
   651             }
   652             print "class ";
   653         }
   654 	print clean_php_identifier($classRef->getName())." ";
   655 
   656 	// print out parent class
   657 	$parentClassRef = $classRef->getParentClass();
   658 	if ($parentClassRef) {
   659 		print "extends {$parentClassRef->getName()} ";
   660 	}
   661 
   662 	// print out interfaces
   663 	$interfacesRef = $classRef->getInterfaces();
   664 	if (count ($interfacesRef) > 0) {
   665 		print $classRef->isInterface() ? "extends " : "implements ";
   666 		$i = 0;
   667 		foreach ($interfacesRef as $interfaceRef) {
   668 			if ($i++ > 0) {
   669 				print ", ";
   670 			}
   671 			print "{$interfaceRef->getName()}";
   672 		}
   673 	}
   674 	print " {\n";
   675 
   676 	// print out traits
   677         $traits = $classRef->getTraits();
   678         if (count($traits)) {
   679             foreach ($traits as $trait => $traitInfo) {
   680                 print_tabs($tabs + 1);
   681                 print 'use ' . $trait . ';';
   682 		print "\n";
   683             }
   684             print "\n";
   685         }
   686 
   687 	// process constants
   688 	$constsRef = $classRef->getConstants();
   689 	if (count ($constsRef) > 0) {
   690 		print_class_constants ($classRef, $constsRef, $tabs + 1);
   691 		print "\n";
   692 	}
   693 
   694 	// process properties
   695 	$propertiesRef = $classRef->getProperties();
   696 	if (!in_array(strtolower($classRef->getName()), $preferHtmlProperties)
   697                 && count ($propertiesRef) > 0) {
   698 		foreach ($propertiesRef as $propertyRef) {
   699 			print_property ($propertyRef, $tabs + 1);
   700 		}
   701 		print "\n";
   702 	} else {
   703         // #188245 - try to find them directly in HTML
   704         $properties = parse_properties_from_html_file('class.' . strtolower($classRef->getName()) . '.html', $classRef->getName());
   705         if (count($properties)) {
   706             foreach ($properties as $property) {
   707                 print_field($property, $tabs + 1);
   708             }
   709             print "\n";
   710         }
   711     }
   712 
   713 	// process methods
   714 	/* @var $classRef ReflectionClass */
   715 	$methodsRef = $classRef->getMethods();
   716 	if (count ($methodsRef) > 0) {
   717 		foreach ($methodsRef as $methodRef) {
   718             /* @var $methodRef ReflectionMethod */
   719             if (in_array(strtolower($methodRef->getName()), $methodBlackList)) {
   720                 continue;
   721             }
   722 			print_method($classRef, $methodRef, $tabs + 1);
   723 		}
   724 		print "\n";
   725 	}
   726 	print_tabs ($tabs);
   727 	print "}\n";
   728 }
   729 
   730 /**
   731  * Prints ReflectionProperty in format of PHP code
   732  * @param ReflectionProperty $propertyRef  object
   733  * @param integer[optional] tabs  number of tabs for indentation
   734  */
   735 function print_property ($propertyRef, $tabs = 0) {
   736 	print_doccomment ($propertyRef, $tabs);
   737 	print_tabs ($tabs);
   738 	print_modifiers ($propertyRef, true);
   739         $name = $propertyRef->getName();
   740         if (substr($name, 0, 1) !== '$') {
   741             $name = '$' . $name;
   742         }
   743         print $name . ";\n";
   744 }
   745 
   746 /**
   747  * Prints Field in format of PHP code
   748  * @param NetBeans_Field $field  object
   749  * @param integer[optional] tabs  number of tabs for indentation
   750  */
   751 function print_field (NetBeans_Field $field, $tabs = 0) {
   752     // documentation
   753     $fieldType = $field->getType();
   754     $fieldDoc = $field->getDocumentation();
   755     $fieldDoc = trim(strip_tags($fieldDoc, '<p>,<strong>,<code>,<a>'));
   756     // replace hyperlinks
   757     $fieldDoc = preg_replace('%<(a|strong)[^>]*>%', '<b>', $fieldDoc);
   758     $fieldDoc = preg_replace('%<p[^>]+>%', '<p>', $fieldDoc);
   759     $fieldDoc = str_replace('</a>', '</b>', $fieldDoc);
   760     $fieldDoc = str_replace('</strong>', '</b>', $fieldDoc);
   761     $fieldDoc = preg_replace('%^<p>(.+)</p>$%s', '<p style="margin-top:0;">\\1</p>', $fieldDoc);
   762 
   763     print_tabs ($tabs);
   764     print "/**\n";
   765     foreach (preg_split('%\n|\r%', $fieldDoc) as $line) {
   766         $line = trim($line);
   767         if (!$line) {
   768             continue;
   769         }
   770         print_tabs($tabs);
   771         print " * $line\n";
   772     }
   773     print_tabs($tabs);
   774     print " * @var $fieldType\n";
   775     print_tabs($tabs);
   776     print " */\n";
   777     // tabs
   778 	print_tabs($tabs);
   779     // modifiers
   780     $print = implode(' ', $field->getModifiers());
   781     $print = str_replace("final", "", $print);
   782     $print = str_replace("abstract", "", $print);
   783     $print = str_replace("readonly", "", $print);
   784     $print = trim($print);
   785     if (!$print) {
   786         // no modifiers
   787         $print = 'public';
   788     }
   789     print $print;
   790     print " ";
   791     $name = $field->getName();
   792     if (substr($name, 0, 1) !== '$') {
   793         $name = '$' . $name;
   794     }
   795     print $name . ";\n";
   796 }
   797 
   798 function print_function ($functionRef, $tabs = 0) {
   799     print_method(null, $functionRef, $tabs);
   800 }
   801 
   802 function print_method ($classRef, $functionRef, $tabs = 0) {
   803 	global $functionsDoc;
   804 	global $processedFunctions;
   805 
   806 	$funckey = make_funckey_from_ref ($functionRef);
   807 	$processedFunctions[$funckey] = true;
   808 
   809 	print "\n";
   810         $modifiers = null;
   811 	print_doccomment ($functionRef, $tabs);
   812 	print_tabs ($tabs);
   813 	if (!($functionRef instanceof ReflectionFunction)) {
   814 		print_modifiers ($functionRef);
   815                 $modifiers = Reflection::getModifierNames($functionRef->getModifiers());
   816 	}
   817 
   818 	print "function ";
   819 	if ($functionRef->returnsReference()) {
   820 		print "&";
   821 	}
   822 	$functionName = $functionRef->getName();
   823 	print "$functionName(";
   824 	$parameters = @$functionsDoc[$funckey]['parameters'];
   825 	if ($parameters) {
   826 		print_parameters ($parameters);
   827 	} else {
   828 		print_parameters_ref ($functionRef->getParameters());
   829 	}
   830 	print ")";
   831         $returntype = sanitizeType(@$functionsDoc[$funckey]['returntype']);
   832         if ($returntype
   833                 && $functionName !== '__construct') {
   834             print ': ' . $returntype;
   835         }
   836         $body = true;
   837         if ($classRef != null && $classRef->isInterface()) {
   838             $body = false;
   839         } elseif (is_array($modifiers)) {
   840             foreach ($modifiers as $modifier) {
   841                 if ($modifier == "abstract") {
   842                     $body = false;
   843                     break;
   844                 }
   845             }
   846         }
   847         if ($body) {
   848             print " {}";
   849         } else {
   850             print ";";
   851         }
   852 	print "\n";
   853 }
   854 
   855 
   856 /**
   857  * Prints ReflectionParameter in format of PHP code
   858  * @param parameters array information from PHP.net documentation
   859  */
   860 function print_parameters ($parameters) {
   861 	$i = 0;
   862 	foreach ($parameters as $parameter) {
   863 		if ($parameter['name'] != "...") {
   864 			if ($i++ > 0) {
   865 				print ", ";
   866 			}
   867                         $type = sanitizeType($parameter['type']);
   868 			if ($type) {
   869 				print "{$type} ";
   870 			}
   871 			if (@$parameter['isreference']) {
   872 				print "&";
   873 			}
   874                         print "\${$parameter['name']}";
   875 			if (@$parameter['isoptional']) {
   876 				if (array_key_exists('defaultvalue', $parameter)) {
   877 					$value = $parameter['defaultvalue'];
   878                                         if ((is_numeric ($value) && $type != 'string')
   879                                                 || in_array(strtolower($value), array('true', 'false', 'null', 'array()'))
   880                                                 || (substr($value, 0, 1) == '\'' && substr($value, -1) == '\'')
   881                                                 || (substr($value, 0, 1) == '"' && substr($value, -1) == '"')
   882                                                 || (substr($value, 0, 2) == '__' && substr($value, -2) == '__')
   883                                                 || isConstant($value)) {
   884                                             // no apostrophes
   885                                         } else {
   886                                             $value = "'{$value}'";
   887                                         }
   888                                         print " = {$value}";
   889 				} else {
   890                                         print " = null";
   891 				}
   892 			}
   893 
   894 		}
   895 	}
   896 }
   897 
   898 /**
   899  * Prints ReflectionParameter in format of PHP code
   900  * @param paramsRef ReflectionParameter[] array of objects
   901  */
   902 function print_parameters_ref ($paramsRef) {
   903 	$i = 0;
   904 	foreach ($paramsRef as $paramRef) {
   905             /* @var $paramRef ReflectionParameter */
   906             if ($paramRef->allowsNull()) {
   907                 echo '?';
   908             }
   909 		if ($paramRef->isArray()) {
   910 			print "array ";
   911 		} else {
   912 			if ($className = get_parameter_classname($paramRef)) {
   913 				print "{$className} ";
   914 			}
   915 		}
   916 		$name = $paramRef->getName() ? $paramRef->getName() : "var".($i+1);
   917 		if ($name != "...") {
   918 			if ($i++ > 0) {
   919 				print ", ";
   920 			}
   921 			if ($paramRef->isPassedByReference()) {
   922 				print "&";
   923 			}
   924 			print "\${$name}";
   925 			if ($paramRef->allowsNull()) {
   926 				print " = null";
   927 			} else if ($paramRef->isDefaultValueAvailable()) {
   928 				$value = $paramRef->getDefaultValue();
   929 				if (!is_numeric ($value)) {
   930 					$value = "'{$value}'";
   931 				}
   932 				print " = {$value}";
   933 			}
   934 		}
   935 	}
   936 }
   937 
   938 /**
   939  * Prints constants in format of PHP code
   940  * @param constants array containing constants, where key is a name of constant
   941  * @param tabs integer[optional] number of tabs for indentation
   942  */
   943 function print_constants ($constants, $tabs = 0) {
   944 	foreach ($constants as $name => $value) {
   945 		print_constant ($name, $value, $tabs);
   946 	}
   947 }
   948 
   949 function print_constant ($name, $value = null, $tabs = 0) {
   950 	global $constantsDoc;
   951 	global $processedConstants;
   952 	$processedConstants [$name] = true;
   953 
   954 	if ($value === null) {
   955 		$value = @constant ($name);
   956 	}
   957 	$value = escape_const_value ($value);
   958 
   959 	$doc = @$constantsDoc[$name]['doc'];
   960 	if ($doc) {
   961 		print "\n";
   962 		print_tabs ($tabs);
   963 		print "/**\n";
   964 		print_tabs ($tabs);
   965 		print " * ".newline_to_phpdoc($doc, $tabs)."\n";
   966 		print_tabs ($tabs);
   967 		print " * @link ".make_url($constantsDoc[$name]['id'])."\n";
   968 		print_tabs ($tabs);
   969 		print " */\n";
   970 	}
   971 	print_tabs ($tabs);
   972 	print "define ('{$name}', {$value});\n";
   973 }
   974 
   975 function escape_const_value ($value) {
   976 	if (is_resource($value)) {
   977 		$value = "\"${value}\"";
   978 	} else if (!is_numeric ($value) && !is_bool ($value) && $value !== null) {
   979 		$value = '"'.addcslashes ($value, "\"\r\n\t").'"';
   980 	} else if ($value === null) {
   981 		$value = "null";
   982 	} else if ($value === false) {
   983 		$value = "false";
   984 	} else if ($value === true) {
   985 		$value = "true";
   986 	}
   987 	return $value;
   988 }
   989 
   990 /**
   991  * Prints class constants in format of PHP code
   992  * @param constants array containing constants, where key is a name of constant
   993  * @param tabs integer[optional] number of tabs for indentation
   994  */
   995 function print_class_constants ($classRef, $constants, $tabs = 0) {
   996     global $constantsDoc;
   997     global $processedConstants;
   998 
   999 
  1000     //$doc = @$constantsDoc[$name]['doc'];
  1001     foreach ($constants as $name => $value) {
  1002         $value = escape_const_value ($value);
  1003         $clsName = $classRef->getName();
  1004         $idx = "$clsName::$name";
  1005         $doc = @$constantsDoc[$idx]['doc'];
  1006         if ($doc) {
  1007             print "\n";
  1008             print_tabs ($tabs);
  1009             print "/**\n";
  1010             print_tabs ($tabs);
  1011             print " * ".newline_to_phpdoc($doc, $tabs)."\n";
  1012             print_tabs ($tabs);
  1013             print " * @link ".make_url($constantsDoc[$idx]['id'])."\n";
  1014             print_tabs ($tabs);
  1015             print " */\n";
  1016         }
  1017         print_tabs ($tabs);
  1018         print "const {$name} = {$value};\n";
  1019     }
  1020 }
  1021 
  1022 /**
  1023  * Prints modifiers of reflection object in format of PHP code
  1024  * @param ref Reflection some reflection object
  1025  */
  1026 function print_modifiers ($ref, $forFields = false) {
  1027 	$modifiers = Reflection::getModifierNames ($ref->getModifiers());
  1028 	if (count ($modifiers) > 0) {
  1029                 $print = implode(' ', $modifiers);
  1030                 if ($forFields) {
  1031                     $print = str_replace("final", "", $print);
  1032                     $print = str_replace("abstract", "", $print);
  1033                     $print = str_replace("readonly", "", $print);
  1034                 }
  1035 		print trim($print);
  1036 		print " ";
  1037 	}
  1038 }
  1039 
  1040 /**
  1041  * Makes PHP Manual URL from the given ID
  1042  * @param id PHP Element ID
  1043  * @return URL
  1044  */
  1045 function make_url ($id) {
  1046 	global $lang;
  1047 	return "http://php.net/manual/{$lang}/{$id}.php";
  1048 }
  1049 
  1050 /**
  1051  * Prints PHPDOC comment before specified reflection object
  1052  * @param ref Reflection some reflection object
  1053  * @param tabs integer[optional] number of tabs for indentation
  1054  */
  1055 function print_doccomment ($ref, $tabs = 0) {
  1056 	global $functionsDoc;
  1057 	global $classesDoc;
  1058         global $fieldsDoc;
  1059         global $methodBlackList;
  1060 
  1061 	$docComment = $ref->getDocComment();
  1062 	if ($docComment) {
  1063 		print_tabs ($tabs);
  1064 		print "{$docComment}\n";
  1065 	}
  1066 	else if ($ref instanceof ReflectionClass) {
  1067 		$refname = strtolower($ref->getName());
  1068 		if (@$classesDoc[$refname]) {
  1069 			print_tabs ($tabs);
  1070 			print "/**\n";
  1071 			$doc = @$classesDoc[$refname]['doc'];
  1072 			if ($doc) {
  1073 				$doc = newline_to_phpdoc ($doc, $tabs);
  1074 				print_tabs ($tabs);
  1075 				print " * {$doc}\n";
  1076 			}
  1077                         // @method
  1078                         foreach ($ref->getMethods() as $method) {
  1079                             if (in_array(strtolower($method->getName()), $methodBlackList)) {
  1080                                 print_magic_method($ref, $method, $tabs);
  1081                             }
  1082                         }
  1083 			if (@$classesDoc[$refname]['id']) {
  1084 				print_Tabs ($tabs);
  1085 				$url = make_url ($classesDoc[$refname]['id']);
  1086 				print " * @link {$url}\n";
  1087 			}
  1088 			print_tabs ($tabs);
  1089 			print " */\n";
  1090 		}
  1091 	}
  1092 	else if ($ref instanceof ReflectionFunctionAbstract) {
  1093 		$funckey = make_funckey_from_ref ($ref);
  1094                 $id = @$functionsDoc[$funckey]['id'];
  1095                 $ver_info = findVerInfo($id);
  1096                 $desc = @$functionsDoc[$funckey]['quickref'];
  1097 		$returntype = "";
  1098                 $returndoc = "";
  1099                 if (strpos($funckey, "::__construct") === false) {
  1100                     $returntype = @$functionsDoc[$funckey]['returntype'];
  1101                     $returndoc = newline_to_phpdoc (@$functionsDoc[$funckey]['returndoc'], $tabs);
  1102                 }
  1103 
  1104 		$paramsRef = $ref->getParameters();
  1105 		$parameters = @$functionsDoc[$funckey]['parameters'];
  1106 
  1107 		if ($desc || count ($paramsRef) > 0 || $parameters || $returntype) {
  1108 			print_tabs ($tabs);
  1109 			print "/**\n";
  1110                         if($ver_info) {
  1111                             print_tabs ($tabs);
  1112                             print " * {$ver_info}<br/>\n";
  1113                         }
  1114                         if ($desc) {
  1115 				print_tabs ($tabs);
  1116 				print " * {$desc}\n";
  1117 			}
  1118 			if (@$functionsDoc[$funckey]['id']) {
  1119 				print_tabs ($tabs);
  1120 				$url = make_url ($functionsDoc[$funckey]['id']);
  1121 				print " * @link {$url}\n";
  1122 			}
  1123                         if (!@$functionsDoc[$funckey]['deprecated']) {
  1124                             if($parameters) {
  1125                                 foreach ($parameters as $parameter) {
  1126                                     print_tabs($tabs);
  1127                                     print " * @param {$parameter['type']} \${$parameter['name']}";
  1128                                     if (@$parameter['isoptional']) {
  1129                                         print " [optional]";
  1130                                     }
  1131                                     $paramdoc = @$parameter['paramdoc'];
  1132                                     if ($paramdoc && $paramdoc != "<p>\n</p>") {
  1133                                         $paramdoc = newline_to_phpdoc(@$parameter['paramdoc'], $tabs);
  1134                                         print " {$paramdoc}";
  1135                                     }
  1136                                     print "\n";
  1137                                 }
  1138                             } else {
  1139                                 $i = 0;
  1140                                 foreach ($paramsRef as $paramRef) {
  1141                                     print_tabs($tabs);
  1142                                     $name = $paramRef->getName() ? $paramRef->getName() : "var".++$i;
  1143                                     print " * @param";
  1144                                     if($className = get_parameter_classname($paramRef)) {
  1145                                         print " {$className}";
  1146                                         if($paramRef->isArray()) {
  1147                                             print "[]";
  1148                                         }
  1149                                     }
  1150                                     print " \${$name}";
  1151                                     if($paramRef->isOptional()) {
  1152                                         print " [optional]";
  1153                                     }
  1154                                     print "\n";
  1155                                 }
  1156                             }
  1157                             if ($returntype || $returndoc) {
  1158                                 if (!$returntype) {
  1159                                     $returntype = 'mixed';
  1160                                 }
  1161                                     print_tabs ($tabs);
  1162                                     print " * @return " . trim("{$returntype} {$returndoc}") . "\n";
  1163                             }
  1164                         }
  1165 			print_tabs ($tabs);
  1166 			print " */\n";
  1167 		}
  1168 	}else if ($ref instanceof ReflectionProperty) {
  1169             $property_from_ref = make_property_from_ref($ref);
  1170             $fieldName = @$fieldsDoc[$property_from_ref]['field'];
  1171             $fieldType = @$fieldsDoc[$property_from_ref]['type'];
  1172             if (isset ($fieldName) && isset ($fieldType)) {
  1173                 print_tabs ($tabs);
  1174                 print "/**\n";
  1175                 print_tabs ($tabs);
  1176                 print " * @var $fieldType\n";
  1177                 print_tabs ($tabs);
  1178                 print " */\n";
  1179             }
  1180         }
  1181 }
  1182 
  1183 function print_magic_method(ReflectionClass $classRef, ReflectionMethod $methodRef, $tabs = 0) {
  1184     global $functionsDoc;
  1185     global $processedFunctions;
  1186 
  1187     $funckey = make_funckey_from_ref($methodRef);
  1188     $processedFunctions[$funckey] = true;
  1189 
  1190     print_tabs($tabs);
  1191     print " * @method ";
  1192     $returntype = @$functionsDoc[$funckey]['returntype'];
  1193     $returndoc = @$functionsDoc[$funckey]['returndoc'];
  1194     if ($returntype
  1195             || $returndoc) {
  1196         if (!$returntype) {
  1197             $returntype = 'mixed';
  1198         }
  1199         print $returntype . " ";
  1200     }
  1201     print $methodRef->getName() . "(";
  1202     $parameters = @$functionsDoc[$funckey]['parameters'];
  1203     if ($parameters) {
  1204         print_parameters($parameters);
  1205     } else {
  1206         print_parameters_ref($methodRef->getParameters());
  1207     }
  1208     print ")";
  1209     $id = @$functionsDoc[$funckey]['id'];
  1210     $ver_info = findVerInfo($id);
  1211     $docComment = @$functionsDoc[$funckey]['quickref'];
  1212     if ($ver_info
  1213             || $docComment) {
  1214         print " ";
  1215         if ($ver_info) {
  1216             print $ver_info;
  1217         }
  1218         if ($docComment) {
  1219             if ($ver_info) {
  1220                 print "<br/>";
  1221             }
  1222             print $docComment;
  1223         }
  1224     }
  1225     print "\n";
  1226 }
  1227 
  1228 /**
  1229  * Converts XML entities to human readable string for PHPDOC
  1230  * @param str string
  1231  * @return string
  1232  */
  1233 function xml_to_phpdoc ($str) {
  1234     $str = str_replace ("&php.ini;", "###(i)###php.ini###(/i)###", $str); // XXX will be replaced in strip_tags_special()
  1235     $str = replace_entities($str);
  1236         $str = strip_tags_special ($str);
  1237 	$str = preg_replace ("/  */", " ", $str);
  1238 	$str = str_replace ("*/", "* /", $str);
  1239 	$str = str_replace ("“", "&quot;", $str);
  1240 	$str = str_replace ("”", "&quot;", $str);
  1241 	$str = preg_replace ("/[\r\n][\t ]/", "\n", $str);
  1242         $str = trim($str);
  1243 	return $str;
  1244 }
  1245 
  1246 /**
  1247  * Converts newlines to PHPDOC prefixes in the given string
  1248  * @param str string
  1249  * @param tabs integer[optional] number of tabs for indentation
  1250  * @return string PHPDOC string
  1251  */
  1252 function newline_to_phpdoc ($str, $tabs = 0) {
  1253 	$str = preg_replace ("@\s*[\r\n]+@", "\n".str_repeat("\t", $tabs)." * ", $str);
  1254 	return $str;
  1255 }
  1256 
  1257 /**
  1258  * Prints specified number of tabs
  1259  * @param tabs integer number of tabs to print
  1260  */
  1261 function print_tabs ($tabs) {
  1262 	print str_repeat("\t", $tabs);
  1263 }
  1264 
  1265 /**
  1266  * Returns class name from given parameter reference, this method is a workaround
  1267  * for the case when exception is thrown from getClass() when such classname does not exist.
  1268  */
  1269 function get_parameter_classname(ReflectionParameter $paramRef) {
  1270 	try {
  1271 		if ($classRef = $paramRef->getClass()) {
  1272 			return $classRef->getName();
  1273 		}
  1274 	} catch (Exception $e) {
  1275 		if (preg_match('/Class (\w+) does not exist/', $e->getMessage(), $matches)) {
  1276 			return $matches[1];
  1277 		}
  1278 	}
  1279 	return null;
  1280 }
  1281 
  1282 /**
  1283  * Starts outputing to the new file
  1284  */
  1285 function begin_file_output() {
  1286 	ob_start();
  1287 	print "<?php\n";
  1288 }
  1289 
  1290 /**
  1291  * Ends outputing, and dumps the output to the specified file
  1292  * @param filename File to dump the output
  1293  */
  1294 function finish_file_output($filename) {
  1295 	//if (file_exists ($filename)) {
  1296 	//	rename ($filename, "{$filename}.bak");
  1297 	//}
  1298 	print "?>\n";
  1299 	file_put_contents (str_replace(" ", "-", $filename), ob_get_contents());
  1300 	ob_end_clean();
  1301 }
  1302 
  1303 /**
  1304  * Strips xml tags from the string like the standard strip_tags() function
  1305  * would do, but also translates some of the docbook tags (such as tables
  1306  * an paragraphs) to proper html tags
  1307  * @param str string
  1308  * @return string
  1309  */
  1310 function strip_tags_special ($str) {
  1311     // methodsynopsis
  1312 //    $str = method_to_phpdoc($str);
  1313     // first mask and translate the tags to preseve
  1314     $str = preg_replace ("/<(\/?)table>/", "###($1table)###", $str);
  1315     $str = str_replace ("<row>", "###(tr valign=\"top\")###", $str);
  1316     $str = str_replace ("</row>", "###(/tr)###", $str);
  1317     $str = preg_replace ("/<(\/?)entry>/", "###($1td)###", $str);
  1318     $str = preg_replace ("/<(\/?)para>/", "###($1p)###", $str);
  1319     $str = preg_replace ("/<(\/?)p>/", "###($1p)###", $str);
  1320     // remove cdata
  1321     $str = str_replace ("<![CDATA[", "###(pre)###", $str);
  1322     $str = str_replace ("]]>", "###(/pre)###", $str);
  1323     // preserve php samples; XXX sample for preg_match_all
  1324     $str = str_replace ("<?php", "###(code)###", $str);
  1325     $str = str_replace ("?>", "###(/code)###", $str);
  1326     // handle "<pre><code>"
  1327     $str = preg_replace ("/###\(pre\)###\s*\n\s*###\(code\)###/", "###(code)###", $str);
  1328     $str = preg_replace ("/###\(\/code\)###\s*\n\s*###\(\/pre\)###/", "###(/code)###", $str);
  1329     // constant & function etc.
  1330     $str = preg_replace ("%<(/)?(constant|function|classname|methodname|methodparam)[^>]*>%", "###(\\1b)###", $str);
  1331     $str = preg_replace ("%<(/)?(parameter)[^>]*>%", "###(\\1i)###", $str);
  1332     // now strip the remaining tags
  1333     $str = strip_tags ($str);
  1334     // and restore the translated ones
  1335     $str = str_replace ("###(", "<", $str);
  1336     $str = str_replace (")###", ">", $str);
  1337     return $str;
  1338 }
  1339 
  1340 // XXX, see set_error_handler
  1341 function method_to_phpdoc($str) {
  1342     $tmp = array();
  1343     $methodsynopsis = preg_match_all ('@<methodsynopsis>.*?<type>(.*?)</type>.*?<methodname>(.*?)</methodname>(.*?)</methodsynopsis>@s', $str, $tmp);
  1344     if (!$methodsynopsis) {
  1345         return $str;
  1346     }
  1347     $functionsDoc = array();
  1348     $parameters = null;
  1349     for ($i = 0; $i < count($tmp); ++$i) {
  1350         $refname = trim($tmp[2][$i]);
  1351         $functionsDoc[$refname]['methodname'] = $refname;
  1352         $parameters = $tmp[3][$i];
  1353         if ($parameters) {
  1354                 if (preg_match_all ('@<methodparam\s*(.*?)>.*?<type>(.*?)</type>.*?<parameter\s*(.*?)>(.*?)</parameter>(?:<initializer>(.+?)</initializer>)?.*?</methodparam>@s', $parameters, $match)) {
  1355                         for ($i = 0; $i < count($match[0]); ++$i) {
  1356                                 $parameter = array (
  1357                                         'type' => trim(str_replace('-', '_', $match[2][$i])), // e.g. OCI-Collection -> OCI_Collection
  1358                                         'name' => clean_php_identifier(trim($match[4][$i])),
  1359                                 );
  1360                                 if (preg_match ('@choice=[\'"]opt[\'"]@', $match[1][$i])) {
  1361                                         $parameter['isoptional'] = true;
  1362                                 }
  1363                                 if (preg_match ('@role=[\'"]reference[\'"]@', $match[3][$i])) {
  1364                                         $parameter['isreference'] = true;
  1365                                 }
  1366                                 if (@strlen(trim($match[5][$i]))) {
  1367                                         $parameter['defaultvalue'] = clean_php_value($match[5][$i]);
  1368                                         $parameter['isoptional'] = true;
  1369                                 }
  1370                                 $functionsDoc[$refname]['parameters'][] = $parameter;
  1371                         }
  1372                 }
  1373                 if (preg_match_all('@<varlistentry\s*.*?>.*?<parameter>(.*?)</parameter>.*?<listitem\s*.*?>(.*?)</listitem>.*?</varlistentry>@s', $parameters, $match)) {
  1374                     for ($i = 0; $i < count($match[0]); $i++) {
  1375                         for ($j = 0; $j < count(@$functionsDoc[$refname]['parameters']); $j++) {
  1376                             if (clean_php_identifier(trim($match[1][$i])) == $functionsDoc[$refname]['parameters'][$j]['name']) {
  1377                                 $functionsDoc[$refname]['parameters'][$j]['paramdoc'] = xml_to_phpdoc ($match[2][$i]);
  1378                                 break;
  1379                             }
  1380                         }
  1381                     }
  1382                 }
  1383         }
  1384     }
  1385     return $str;
  1386 }
  1387 
  1388 function parse_entities($phpdocDir, $lang) {
  1389     $entities = array();
  1390     parse_entities_from_file($entities, $phpdocDir, "/{$lang}/language-defs.ent");
  1391     parse_entities_from_file($entities, $phpdocDir, "/{$lang}/language-snippets.ent");
  1392     parse_entities_from_file($entities, $phpdocDir, '/doc-base/docbook/docbook-xml/ent/isonum.ent');
  1393     parse_entities_from_file($entities, $phpdocDir, '/doc-base/entities/global.ent');
  1394     return $entities;
  1395 }
  1396 function parse_entities_from_file(array &$entities, $phpdocDir, $filepath) {
  1397     $content = file_get_contents($phpdocDir . $filepath);
  1398     $matches = array();
  1399     preg_match_all('%\!ENTITY\s+(\S+)\s+([\'"])([^\\2]+?)\\2\s*>%m', $content, $matches);
  1400     if (array_key_exists(1, $matches) && count($matches[1])) {
  1401         for ($i = 0; $i < count($matches[2]); $i++) {
  1402             $entities['&' . $matches[1][$i] . ';'] = $matches[3][$i];
  1403         }
  1404     }
  1405 }
  1406 function replace_entities($text) {
  1407     global $entities;
  1408     $matches = array();
  1409     while (preg_match_all('%(\&(?!#)\S+?\;)%', $text, $matches)) {
  1410         if (count($matches[1])) {
  1411             foreach ($matches[1] as $e) {
  1412                 $replace = null;
  1413                 if (array_key_exists($e, $entities)) {
  1414                     $replace = $entities[$e];
  1415                 }
  1416                 if ($replace === null) {
  1417                     switch ($e) {
  1418                         case '&$a));':
  1419                             // code sample
  1420                         case '&reference.strings.charsets;':
  1421                         case '&reference.intl.inctimezoneparam;':
  1422                         case '&reference.intl.incfieldparam;':
  1423                             // entity not found
  1424                             break;
  1425                         default:
  1426                             die('Entity "' . $e . '" not found' . "\n");
  1427                     }
  1428                 }
  1429                 $text = str_replace($e, $replace, $text);
  1430             }
  1431         }
  1432     }
  1433     // return back &lt; and &gt;
  1434     $keep = array(
  1435         '&#38;#60;' => '&lt;',
  1436         '&#x0003E;' => '&gt;',
  1437     );
  1438     return str_replace(array_keys($keep), $keep, $text);
  1439 }
  1440 
  1441 function parse_properties_from_html_file($filepath, $classname) {
  1442     $file = DOC_URL . $filepath;
  1443     if (!is_file($file)) {
  1444         return array();
  1445         //die('Cannot parse properties from non-existing file: ' . $file);
  1446     }
  1447     $fields = array();
  1448     $html = new DOMDocument();
  1449     $html->preserveWhiteSpace = false;
  1450     @$html->loadHtmlFile($file);
  1451     $xpath = new DOMXPath($html);
  1452     // documentation
  1453     $doc = array();
  1454     $docNodes = $xpath->query('//div[@id="' . strtolower($classname) . '.props"]/dl');
  1455     if (!$docNodes->length) {
  1456         //die('Documentation not found for properties in file: ' . $file);
  1457     } elseif ($docNodes->length > 1) {
  1458         die('More documentations found for properties in file: ' . $file);
  1459     }
  1460     if ($docNodes->length) {
  1461         $fieldname = null;
  1462         foreach ($docNodes->item(0)->childNodes as $node) {
  1463             if ($node->nodeName == 'dt') {
  1464                 $fieldname = trim($node->nodeValue);
  1465             } elseif ($node->nodeName == 'dd') {
  1466                 $tmp = new DOMDocument();
  1467                 foreach ($node->childNodes as $child) {
  1468                     $tmp->appendChild($tmp->importNode($child, true));
  1469                 }
  1470                 $doc[$fieldname] = $tmp->saveHTML();
  1471             } else {
  1472                 //die('Unknown node name: ' . $node->nodeName);
  1473             }
  1474         }
  1475     }
  1476 
  1477     // fields
  1478     $fieldNodes = $xpath->query('//div[@class="classsynopsis"]//div[@class="fieldsynopsis"]');
  1479     foreach ($fieldNodes as $fieldNode) {
  1480         $field = new NetBeans_Field();
  1481         // name
  1482         $varnameNodes = $xpath->query('var//var[@class="varname"]', $fieldNode);
  1483         if (!$varnameNodes->length) {
  1484             die('Varname not found for property in file: ' . $file);
  1485         } elseif ($varnameNodes->length > 1) {
  1486             die('More varnames found for property in file: ' . $file);
  1487         }
  1488         $field->setName($varnameNodes->item(0)->nodeValue);
  1489         // modifiers
  1490         $modifierNodes = $xpath->query('span[@class="modifier"]', $fieldNode);
  1491         foreach ($modifierNodes as $modifierNode) {
  1492             $modifier = $modifierNode->nodeValue;
  1493             // XXX
  1494             if ($modifier == 'const') {
  1495                 // constant => do nothing
  1496                 return array();
  1497             }
  1498             $field->addModifier($modifier);
  1499         }
  1500         // type
  1501         $typeNodes = $xpath->query('span[@class="type"]', $fieldNode);
  1502         if ($typeNodes->length > 1) {
  1503             die('More types found for property ' . $field->getName() . ' in file: ' . $file);
  1504         }
  1505         $field->setType($typeNodes->item(0)->nodeValue);
  1506         // documentation
  1507         if (array_key_exists($field->getName(), $doc)) {
  1508             $field->setDocumentation($doc[$field->getName()]);
  1509         }
  1510         // all ok
  1511         $fields[] = $field;
  1512     }
  1513     return $fields;
  1514 }
  1515 
  1516 class NetBeans_Field {
  1517 
  1518     private $modifiers = array();
  1519     private $type;
  1520     private $name;
  1521     private $value;
  1522     private $documentation;
  1523 
  1524 
  1525     public function getModifiers() {
  1526         return $this->modifiers;
  1527     }
  1528 
  1529     /**
  1530      * @return \NetBeans_Field
  1531      */
  1532     public function addModifier($modifier) {
  1533         $this->modifiers[] = $modifier;
  1534         return $this;
  1535     }
  1536 
  1537     /**
  1538      * @return \NetBeans_Field
  1539      */
  1540     public function setModifiers($modifiers) {
  1541         $this->modifiers = $modifiers;
  1542         return $this;
  1543     }
  1544 
  1545     public function getType() {
  1546         return $this->type;
  1547     }
  1548 
  1549     /**
  1550      * @return \NetBeans_Field
  1551      */
  1552     public function setType($type) {
  1553         $this->type = $type;
  1554         return $this;
  1555     }
  1556 
  1557     public function getName() {
  1558         return $this->name;
  1559     }
  1560 
  1561     /**
  1562      * @return \NetBeans_Field
  1563      */
  1564     public function setName($name) {
  1565         $this->name = $name;
  1566         return $this;
  1567     }
  1568 
  1569     public function getValue() {
  1570         return $this->value;
  1571     }
  1572 
  1573     /**
  1574      * @return \NetBeans_Field
  1575      */
  1576     public function setValue($value) {
  1577         $this->value = $value;
  1578         return $this;
  1579     }
  1580 
  1581     public function getDocumentation() {
  1582         return $this->documentation;
  1583     }
  1584 
  1585     /**
  1586      * @return \NetBeans_Field
  1587      */
  1588     public function setDocumentation($documentation) {
  1589         $this->documentation = trim($documentation);
  1590         return $this;
  1591     }
  1592 
  1593 }
  1594 
  1595 function sanitizeType($type) {
  1596     if (!trim($type)) {
  1597         return '';
  1598     }
  1599     if (strpos($type, '|') !== false) {
  1600         // ignore 'MyClass|YourClass' cases
  1601         return '';
  1602     }
  1603     if (in_array($type, [
  1604         'mixed',
  1605         'object',
  1606         'callback',
  1607         'resource',
  1608         'bitmask',
  1609         'name',
  1610         'number',
  1611         'scalar',
  1612     ])) {
  1613         return '';
  1614     }
  1615     $convert = [
  1616         'boolean' => 'bool',
  1617     ];
  1618     return str_replace(array_keys($convert), $convert, $type);
  1619 }
  1620 
  1621 function isConstant($value) {
  1622     $values = explode(' | ', $value);
  1623     foreach ($values as $v) {
  1624         if (!preg_match('/^(\\w+\\:\\:)?[A-Z0-9_]+$/', $v)) {
  1625             return false;
  1626         }
  1627     }
  1628     return true;
  1629 }
  1630 
  1631 /**
  1632  * Prints usage help to the screen, and exits from program
  1633  */
  1634 function show_help() {
  1635 	global $argv0;
  1636 
  1637 	die (<<<EOF
  1638 USAGE: {$argv0} [options] <PHP.net documentation directory>
  1639 
  1640 Where options are:
  1641 
  1642 -help		Show this help.
  1643 -nosplit	Don't split output to different files.
  1644 -split		Split output to different files (one file per PHP extension).
  1645 -lang		Specify the language("en" by default). e.g. -lang en, -lang ja
  1646 -output 	Output directory name("php" by default).
  1647 
  1648 EOF
  1649 	);
  1650 }
  1651 
  1652 function show_message($message) {
  1653 	echo $message . PHP_EOL;
  1654 }
  1655 
  1656 ?>