Gtk_Dumper.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897
  1. <?php
  2. /**
  3. * PHP-GTK Stub generator
  4. *
  5. * This program can be run on any system with PHP-GTK installed.
  6. * It generates a skeleton file containing all classes present
  7. * in the currently active PHP-GTK extension, with their
  8. * constants, methods, and signatures thereof.
  9. *
  10. * This file can be installed on various IDEs to enable code
  11. * completion when the IDE does not use the PHP-GTK interpreter
  12. * itself.
  13. *
  14. * Installation on Eclipse PDT
  15. * To enable code completion for PHP-GTK on Eclipse PDT:
  16. * 1. create a "PHP-GTK Lookup" PHP project
  17. * 2. run this file and save its output as a PHP file, like "php-reference.php"
  18. * 3. place the generated file in a directory of its own, within the "PHP Lookup" project
  19. * 4. When creating a new PHP Project, add the "PHP Lookup" project in the list of includes
  20. *
  21. * Similar steps should work in other IDEs
  22. *
  23. * Do NOT include/require it in your actual PHP source code:
  24. * it would clash with the actual PHP-GTK symbols.
  25. *
  26. * This version has been tested on the following standard PGP-GTK2 builds:
  27. * - 2.0.0-dev "leap day special"
  28. * - 2.0.1 "you knew this was coming"
  29. *
  30. * @copyright Frederic G. MARAND
  31. * @license CeCILL Version 2.0
  32. * @link http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
  33. * @version $Id: Gtk_Dumper.php,v 1.1 2008-05-24 06:40:51 cvs Exp $
  34. */
  35. error_reporting(E_ALL | E_STRICT);
  36. define('GTK_DUMPER_VERSION', '$Id: Gtk_Dumper.php,v 1.1 2008-05-24 06:40:51 cvs Exp $');
  37. /**
  38. * Obtain the reflection info about the PHP-GTK extension
  39. * @return string
  40. */
  41. function getExtensionInfo()
  42. {
  43. $arExtensions = get_loaded_extensions();
  44. if (!in_array('php-gtk', $arExtensions))
  45. {
  46. die('PHP-GTK not loaded');
  47. }
  48. $ret = "/**\n"
  49. . " * PHP-GTK skeletons, generated from the extension using: \n"
  50. . " * " . GTK_DUMPER_VERSION . PHP_EOL
  51. . " * \n";
  52. $ext = new ReflectionExtension('php-gtk');
  53. $version = $ext->getVersion()
  54. ? $ext->getVersion()
  55. : 'No version info';
  56. $ret .= sprintf
  57. (
  58. " * Name : %s\n" .
  59. " * Version : %s\n" .
  60. " * INI entries : %d\n",
  61. $ext->getName(),
  62. $version,
  63. count($ext->getINIEntries())
  64. );
  65. foreach ($ext->getINIEntries() as $entry => $value)
  66. {
  67. $ret .= ' * - ' . $entry . ' = ' . $value . PHP_EOL;
  68. }
  69. $ret .= " */\n";
  70. return $ret;
  71. }
  72. /**
  73. * internal use class to return the origin of a class, interface, method, object, or function
  74. */
  75. class GtkOriginator
  76. {
  77. /**
  78. * @param ReflectionFunctionAbstract $x
  79. */
  80. public function __construct($x)
  81. {
  82. $arMethodNames = get_class_methods($x);
  83. if (!in_array('isInternal', $arMethodNames) or !in_array('isUserDefined', $arMethodNames))
  84. {
  85. throw new ReflectionException('GtkOriginator() takes classes implementing isInternal()/isUserDefined(). '
  86. . get_class($x)
  87. . print_r($arMethodNames, true));
  88. }
  89. $this->x = $x;
  90. }
  91. /**
  92. * A consistency-checked readable form of the origin modifier
  93. *
  94. * @return string
  95. */
  96. public function getOrigin()
  97. {
  98. $mask = $this->x->isInternal() << 1 | $this->x->isUserDefined();
  99. switch ($mask)
  100. {
  101. case 0: $ret = 'unknown_origin'; break;
  102. case 1: $ret = 'user-defined' ; break;
  103. case 2: $ret = 'internal' ; break;
  104. case 3:
  105. throw new ReflectionException("Inconsistent origin for $this->x->name().");
  106. break;
  107. // no possible other case
  108. }
  109. return $ret;
  110. }
  111. }
  112. /**
  113. * The PHP-GTK 2.0 extension has some specific quirks:
  114. * - only a limited subset of parameter attributes is used
  115. * - optional parameters are visible, but not their default values
  116. * - some parameters have invalid names: the first parameter in
  117. * GtkColorMap::alloc_color is "$color OR red"
  118. * - some parameters are named as $... to denote extended parameter lists
  119. *
  120. * Number of parameters with given attribute combinations in version 2.0.0.0 of php_gtk.dll:
  121. * - none: 21098
  122. * - allowsNull: 2 (GtkIconView::set_drag_dest_item($pos) and Gdk::event_request_motions($event))
  123. * - isOptional: 2412
  124. * - valid class name: 132
  125. * - valid class name + allowsNull: 5888
  126. * - valid class name + isOptional: 1 (GtkIconView::__construct(GtkTreeModel $model))
  127. * - valid class name + isOptional + allowsNull: 76
  128. */
  129. class GtkReflectionParameter extends ReflectionParameter
  130. {
  131. /**
  132. * Format the parameter as a valid PHP declaration.
  133. * The means the information is not necessarily complete
  134. * in comparison with the one available from __toString()
  135. *
  136. * The return value is an assoc array with two keys:
  137. * - valid: if true, this is a valid PHP parameter declaration; otherwise it is a PHP comment containing a declaration
  138. * - string: the actual result
  139. *
  140. * "Invalid" results typically happen when a parameter is optional, but
  141. * without a default value. In that case, the comment contains the
  142. * parameter declaration within a comment, meaning it cannot be inserted
  143. * as such in a PHP function declaration.
  144. *
  145. * @return array
  146. */
  147. public function asPhp()
  148. {
  149. $ret = '';
  150. $bitDA = $this->isDefaultValueAvailable() ? 1 : 0;
  151. $bitAN = $this->allowsNull() ? 1 : 0;
  152. $bitOP = $this->isOptional() ? 1 : 0;
  153. /**
  154. * An exception can occur on getClass():
  155. * GtkIconView::set_drag_dest_item($pos)
  156. * getting its class throws a ReflectionException:
  157. * "Class GtkIconViewDropPosition does not exist"
  158. * so we ignore it.
  159. */
  160. try
  161. {
  162. $typeName = $this->getClass();
  163. }
  164. catch (ReflectionException $e)
  165. {
  166. $typeName = NULL;
  167. }
  168. $bitCN = empty($typeName) ? 0 : 1;
  169. $bitAR = $this->isArray() ? 1 : 0;
  170. $bitDN = $bitDA
  171. ? (($this->getDefaultValue() === NULL) ? 1: 0)
  172. : 0;
  173. $mask= $bitDA + ($bitAN << 1) + ($bitOP << 2) + ($bitCN << 3) + ($bitAR << 4) + ($bitDN << 5);
  174. /**
  175. * @todo sanitize name
  176. */
  177. $name = $this->name;
  178. $name = str_replace(' ', '_', $name);
  179. // echo "// $name\n";
  180. $ret = array('valid' => TRUE);
  181. switch ($mask)
  182. {
  183. case 0: // plain
  184. $ret['string'] = '$' . $name;
  185. break;
  186. case 2: // isDefaultAvailable
  187. try
  188. {
  189. $def = var_export($this->getDefaultValue(), TRUE);
  190. }
  191. catch (ReflectionException $e)
  192. {
  193. $def = 'NULL /* Exception: ' . $e->getMessage() . ' */';
  194. }
  195. $ret['string'] = "\$$name = " . $def;
  196. break;
  197. case 4: // isOptional
  198. $ret['string'] = "/* \$$name */";
  199. $ret['valid'] = FALSE;
  200. break;
  201. case 8: // valid class name
  202. $ret['string'] = $this->getClass()->name . ' $' . $name;
  203. break;
  204. case 10: // valid class name | allowsNull
  205. $ret['string'] = $this->getClass()->name . ' $' . $name . " /* or NULL */";
  206. break;
  207. case 12: // valid class name | isOptional
  208. $ret['string'] = '/* ' . $this->getClass()->name . ' $' . $name . ' */';
  209. $ret['valid'] = FALSE;
  210. case 14: // valid class name | isOptional | allowsNull
  211. $ret['string'] = $this->getClass()->name . ' $' . $name . ' = NULL';
  212. break;
  213. case 16: // array
  214. $ret['string'] = 'array $' . $name;
  215. break;
  216. default:
  217. throw new ReflectionException("Unhandled combination of attributes " . sprintf('0x%02X', $mask) . " for parameter $name.");
  218. break;
  219. }
  220. return $ret;
  221. }
  222. }
  223. /**
  224. * Extends the ReflectionMethod to enable generation of PHP source code
  225. * instead of pseudo-readable code as in __toString
  226. *
  227. */
  228. class GtkReflectionMethod extends ReflectionMethod
  229. {
  230. /**
  231. * PHP-GTK2 includes some problematic method names, which clash
  232. * with reserver words in PHP (foreach, unset)
  233. *
  234. * @param string $name
  235. * @return string
  236. */
  237. protected function fixName($name)
  238. {
  239. /**
  240. * Fix PHP-GTK 2.0.0.0 special names
  241. */
  242. switch ($name)
  243. {
  244. case 'foreach':
  245. $ret = 'foreach_method';
  246. break;
  247. case 'unset':
  248. $ret = 'unset_method';
  249. break;
  250. default:
  251. $ret = $name;
  252. break;
  253. }
  254. return $ret;
  255. }
  256. /**
  257. * Some stats from PHP-GTK 2.0.0.0:
  258. *
  259. * - 0x0100 plain: 29443
  260. * - 0x0101 static: 2539
  261. * - 0x0104 public final: 24
  262. * - 0x0108 public | undocumented 0x0008: 479
  263. * - 0x2100 public | undocumented 0x2000: 243 (all of them constructors)
  264. * - 0x2400 private | undocumented 0x2000: 2 (both of them constructors)
  265. * - 0x8404 private final | undocumented 0x8000: 4 (PhpGtk*Exception::__clone())
  266. *
  267. * @return string
  268. */
  269. public function asPhp()
  270. {
  271. $ret = ' ';
  272. /**
  273. * built a more complete attribute list tant getModifiers()
  274. */
  275. $bitST = $this->isStatic() ? ReflectionMethod::IS_STATIC : 0; // 0x0001
  276. $bitAB = $this->isAbstract() ? ReflectionMethod::IS_ABSTRACT : 0; // 0x0002
  277. $bitFI = $this->isFinal() ? ReflectionMethod::IS_FINAL : 0; // 0x0004
  278. $bitPU = $this->isPublic() ? ReflectionMethod::IS_PUBLIC : 0; // 0x0100
  279. $bitPO = $this->isProtected() ? ReflectionMethod::IS_PROTECTED: 0; // 0x0200
  280. $bitPV = $this->isPrivate() ? ReflectionMethod::IS_PRIVATE : 0; // 0x0400
  281. $bitCO = $this->isConstructor() ? 0x00004000 : 0; // no visible conflict
  282. $bitDE = $this->isDeprecated() ? ReflectionFunction::IS_DEPRECATED: 0; // 0x00040000
  283. $bitDS = $this->isDestructor() ? 0x10000000 : 0; // no visible conflict
  284. /**
  285. * PHP-GTK2 does not fill in these elements, so we do not use them:
  286. *
  287. 'file ' . $this->getFileName()
  288. 'startLine ' . $this->getStartLine()
  289. 'endLine ' . $this->getEndLine()
  290. 'docComment ' . $this->getDocComment()
  291. 'static Vars ' . implode(', ', $this->getStaticVariables())
  292. */
  293. $mask = $bitST | $bitAB | $bitFI | $bitPU | $bitPO | $bitPV | $bitCO | $bitDE | $bitDS
  294. | $this->getModifiers();
  295. if ($bitCO and $this->name != '__construct')
  296. {
  297. throw ReflectionException("Incorrectly named constructor $this->name.");
  298. }
  299. if ($bitDS and $this->name != '__destruct')
  300. {
  301. throw ReflectionException("Incorrectly named destructor $this->name.");
  302. }
  303. $name = $this->fixName($this->name);
  304. $isInterface = $this->getDeclaringClass()->isInterface();
  305. if ($isInterface)
  306. {
  307. if (!($mask & self::IS_ABSTRACT))
  308. {
  309. throw("Non-abstract method $name in interface declaration.");
  310. }
  311. $mask &= !(self::IS_ABSTRACT // implicit in interfaces
  312. | self::IS_PUBLIC // implicit in interfaces
  313. | self::IS_PROTECTED // forbidden in interfaces
  314. | self::IS_PRIVATE // forbidden in interfaces
  315. );
  316. }
  317. $origin = new GtkOriginator($this);
  318. $origin = $origin->getOrigin();
  319. switch ($mask)
  320. {
  321. case 0x0000:
  322. $ret .= "/* $origin */ function ";
  323. break;
  324. case 0x0100:
  325. $ret .= "public /* $origin */ function ";
  326. break;
  327. case 0x0101:
  328. $ret .= "static public /* $origin */ function ";
  329. break;
  330. case 0x0102:
  331. $ret .= "abstract public /* $origin */ function ";
  332. break;
  333. case 0x0103:
  334. $ret .= "static abstract public /* $origin */ function ";
  335. break;
  336. case 0x0104:
  337. $ret .= "final public /* $origin */ function ";
  338. break;
  339. case 0x0108:
  340. $ret .= "public /* 0x0008 $origin */ function ";
  341. break;
  342. case 0x2102:
  343. $ret .= "public /* 0x2000 $origin */ function ";
  344. break;
  345. case 0x6100:
  346. $ret .= "public /* 0x6000 $origin */ function ";
  347. break;
  348. case 0x6400:
  349. $ret .= "private /* 0x6000 $origin */ function ";
  350. break;
  351. case 0x8404:
  352. $ret .= "final private /* 0x8000 $origin */ function ";
  353. break;
  354. default:
  355. throw new ReflectionException("Unhandled method attribute set " . sprintf('0x%08x', $mask)
  356. . " for " . $this->getDeclaringClass()->name . '::' . $this->name . '().');
  357. break;
  358. }
  359. /**
  360. * Not used in PHP-GTK 2.0.0.0
  361. */
  362. if ($this->returnsReference())
  363. {
  364. $ret .= '&';
  365. }
  366. $ret .= $name . " // "
  367. . $this->getNumberOfParameters() . ' parameters, '
  368. . $this->getNumberOfRequiredParameters() . " required."
  369. . "\n (\n ";
  370. $arParamStrings = array();
  371. $arParamComments = array();
  372. foreach ($this->getParameters() as $param)
  373. {
  374. $paramVector = $param->asPhp();
  375. if ($paramVector['valid'])
  376. {
  377. $arParamStrings[] = $paramVector['string'];
  378. }
  379. else
  380. {
  381. $arParamComments[] = $paramVector['string'];
  382. }
  383. }
  384. // @todo tidy formatting: on methods without parameters, one gets a useless empty line
  385. $paramString = implode(",\n ", $arParamStrings);
  386. if (count($arParamComments))
  387. {
  388. $paramString .= "\n " . implode("\n ", $arParamComments);
  389. }
  390. $ret .= $paramString
  391. . "\n )";
  392. $ret .= $isInterface ? ";\n\n" : " {}\n\n";
  393. return $ret;
  394. }
  395. /**
  396. * Convert the ReflectionParameter array to a GtkReflectionParameter array
  397. *
  398. * @return GtkReflectionParameter[]
  399. */
  400. function getParameters()
  401. {
  402. $arParams1 = parent::getParameters();
  403. $arParams2 = array();
  404. foreach($arParams1 as $param)
  405. {
  406. $pos = $param->getPosition();
  407. $arParams2[] = new GtkReflectionParameter(array($this->class, $this->name), $pos);
  408. }
  409. unset($arParams1);
  410. return $arParams2;
  411. }
  412. }
  413. /**
  414. * An extension to the ReflectionClass, able to output
  415. * reflection information about an interface either as
  416. * structured content or PHP source code
  417. */
  418. class GtkReflectionInterface extends GtkReflectionClass
  419. {
  420. /**
  421. * Make sure the class/interface information matches
  422. * the actual class
  423. * @throws ReflectionException
  424. * @return void
  425. */
  426. protected function getHeader()
  427. {
  428. /**
  429. * Consistency check
  430. */
  431. if (!$this->isInterface())
  432. {
  433. throw new ReflectionException("Interface $this->name is listed as being a plain class.");
  434. }
  435. $ret = $this->getModifiersString()
  436. . " interface $this->name";
  437. return $ret;
  438. }
  439. }
  440. /**
  441. * Extend the ReflectionClass to support PHP rendering
  442. * There are no doccomments in PHP-GTK classes, so no
  443. * method around $this->getDocComment()
  444. * Same for interface $this->getProperties()
  445. */
  446. class GtkReflectionClass extends ReflectionClass
  447. {
  448. /**
  449. * @return string
  450. */
  451. protected function getModifiersString()
  452. {
  453. $ret = array();
  454. $mask = $this->getModifiers();
  455. if ($mask & self::IS_EXPLICIT_ABSTRACT) { $ret[] = 'abstract'; }
  456. if ($mask & self::IS_FINAL) { $ret[] = 'final'; }
  457. if ($mask & self::IS_IMPLICIT_ABSTRACT) { $ret[] = '/* abstract */'; }
  458. if ($this->isInstantiable()) { $ret[] = '/* instantiable */'; }
  459. if ($this->isIterateable()) { $ret[] = '/* iterateable */'; }
  460. $origin = new GtkOriginator($this);
  461. $origin = $origin->getOrigin();
  462. $ret[] = "/* $origin */";
  463. $ret = implode(' ', $ret);
  464. $ret = str_replace(' */ /* ', ' ', $ret);
  465. return $ret;
  466. }
  467. /**
  468. * Make sure the class/interface information matches
  469. * the actual class
  470. * @throws ReflectionException
  471. * @return void
  472. */
  473. protected function getHeader()
  474. {
  475. /**
  476. * Consistency check
  477. */
  478. if ($this->isInterface())
  479. {
  480. throw new ReflectionException("Class $this->name is listed as being an interface.");
  481. }
  482. $ret = $this->getModifiersString()
  483. . " class $this->name";
  484. return $ret;
  485. }
  486. /**
  487. * return the inherited constants
  488. */
  489. protected function getInheritedConstants()
  490. {
  491. $ret = array();
  492. $arAncestry = Gtk_Dumper::getClassAncestry($this->name);
  493. array_pop($arAncestry); // remove current class
  494. foreach($arAncestry as $ancestorName)
  495. {
  496. $rAncestor = new ReflectionClass($ancestorName);
  497. $arAncestorConstants = $rAncestor->getConstants();
  498. $ret = array_merge($ret, $arAncestorConstants);
  499. unset($rAncestor);
  500. }
  501. return $ret;
  502. }
  503. /**
  504. * return the "constant" clauses
  505. * @return string
  506. */
  507. protected function getConstantsString()
  508. {
  509. $arConstants = $this->getConstants();
  510. $ret = '';
  511. $arInheritedConstants = $this->getInheritedConstants();
  512. foreach ($arConstants as $name => $value)
  513. {
  514. if (array_key_exists($name, $arInheritedConstants) and ($arInheritedConstants[$name] == $value))
  515. {
  516. continue; // skip constant: it has not changed from the parent class
  517. }
  518. /**
  519. * These reserved words are used for Gdk blit modes
  520. */
  521. if (in_array($name, array('XOR', 'OR', 'AND')))
  522. {
  523. $comment = "// Actual name is $name, which is reserved in PHP";
  524. $name = "${name}_BLIT"; //
  525. }
  526. else
  527. {
  528. $comment = NULL;
  529. }
  530. if (is_string($value))
  531. {
  532. $value = "'$value'";
  533. }
  534. $ret .= " const $name = $value"
  535. . (empty($comment) ? ";\n" : "; $comment\n");
  536. }
  537. $ret = (empty($ret) and !$this->isInterface()) // Interfaces don't have constants anyway
  538. ? " // No constants\n"
  539. : $ret;
  540. return $ret;
  541. }
  542. /**
  543. * Format the class as a valid PHP declaration.
  544. * The means the information is not necessarily complete
  545. * in comparison with the one available from __toString()
  546. *
  547. * @todo tidy up vertical spacing
  548. * @return string
  549. */
  550. public function asPhp()
  551. {
  552. // 1. the "class" line
  553. $ret = $this->getHeader() ;
  554. // 2. the parenting
  555. $parent = $this->getParentClass();
  556. if ($parent)
  557. {
  558. $ret .= " extends " . $parent->name;
  559. }
  560. // 3. the interfaces
  561. $arInterfaceNames1 = $this->getInterfaceNames();
  562. $arInterfaceNames2 = array();
  563. foreach ($arInterfaceNames1 as $interface)
  564. {
  565. // @link http://www.php.net/~helly/php/ext/spl/interfaceTraversable.html
  566. if ($interface == 'Traversable')
  567. {
  568. $ret .= " // Traversable cannot be implement in userland PHP\n"
  569. . " // see http://www.php.net/~helly/php/ext/spl/interfaceTraversable.html\n";
  570. continue;
  571. }
  572. $arInterfaceNames2[] = $interface;
  573. }
  574. $ret .= empty($arInterfaceNames2)
  575. ? NULL
  576. : "\n implements "
  577. . implode(', ', $arInterfaceNames2);
  578. $ret .= "\n {\n";
  579. // 4. the constants
  580. $constantStrings = $this->getConstantsString();
  581. if (!empty($constantStrings))
  582. {
  583. $ret .= $constantStrings . PHP_EOL;
  584. }
  585. // 5. the methods
  586. foreach ($this->getMethods() as $method)
  587. {
  588. if ($method->getDeclaringClass()->name == $this->name)
  589. {
  590. $ret .= $method->asPhp();
  591. }
  592. }
  593. $ret .= " }\n";
  594. return $ret;
  595. }
  596. /**
  597. * Convert the ReflectionMethod array to a GtkReflectionMethod array
  598. *
  599. * @return GtkReflectionMethod[]
  600. */
  601. function getMethods($filter = NULL)
  602. {
  603. $arMethods1 = parent::getMethods();
  604. $arMethods2 = array();
  605. foreach($arMethods1 as $method)
  606. {
  607. $arMethods2[] = new GtkReflectionMethod($this->name, $method->name);
  608. }
  609. unset($arMethods1);
  610. return $arMethods2;
  611. }
  612. }
  613. /**
  614. * Static methods allow lists of classes and interfaces
  615. * to be obtained, from which an exhaustive dump of the
  616. * classes and interfaces in an extension can be obtained
  617. * using the normal methods of the class.
  618. */
  619. class Gtk_Dumper
  620. {
  621. /**
  622. * The Reflection class for the class under examination
  623. * @var ReflectionClass
  624. */
  625. protected $class;
  626. /**
  627. * The name of the class under examination
  628. * This is a shortcut to avoid constant reuse
  629. * of ReflectionClass::getName()
  630. * @var string
  631. */
  632. protected $name;
  633. /**
  634. * @param string $name
  635. */
  636. public function __construct($name)
  637. {
  638. $this->name = $name;
  639. $this->class = new ReflectionClass($name);
  640. }
  641. /**
  642. * Return the hierarchy of parents to a class as an array starting
  643. * at the root class
  644. *
  645. * @param string $className
  646. * @return array
  647. */
  648. static public function getClassAncestry($className)
  649. {
  650. $ret = array();
  651. $class = new ReflectionClass($className);
  652. do
  653. {
  654. array_unshift($ret, $class->getName());
  655. $class = $class->getParentClass();
  656. } while($class);
  657. return $ret;
  658. }
  659. /**
  660. * List the classes in PHP-GTK
  661. *
  662. * Regrettably, the Reflection information on PHP-GTK2 classes
  663. * is incomplete: it does not return the extension information on
  664. * ReflectionClass::getExtension() and ReflectionClass::getExtensionName()
  665. * so we have to use hard-coded information
  666. *
  667. * @return array
  668. */
  669. static public function getPhpGtkClassNames()
  670. {
  671. static $phpGtkRoots = array
  672. (
  673. /**
  674. * These are the PHP-GTK 2 root classes
  675. */
  676. 'Atk',
  677. 'GBoxed',
  678. 'Gdk',
  679. 'GdkAtom',
  680. 'Glade',
  681. 'GObject',
  682. 'GParamSpec',
  683. 'GPointer',
  684. 'GType',
  685. 'Gtk',
  686. 'GtkAccessible',
  687. 'GtkAtom',
  688. 'GtkTreeModelRow',
  689. 'GtkTreeModelRowIterator',
  690. 'Pango',
  691. /**
  692. * This one has an ancestor outside the extension
  693. */
  694. 'PhpGtkException',
  695. );
  696. $arClassNames = get_declared_classes();
  697. $ret = array();
  698. foreach ($arClassNames as $className)
  699. {
  700. $rclass = new ReflectionClass($className);
  701. $extName = $rclass->getExtensionName();
  702. /**
  703. * The PHP-GTK extension does not define a value for getExtensionName()
  704. * so we can save time, ignore classes known to come from other extensions
  705. */
  706. if (!empty($extName))
  707. {
  708. continue;
  709. }
  710. /**
  711. * we only want non-interface classes in this list
  712. */
  713. if ($rclass->isInterface())
  714. {
  715. continue;
  716. }
  717. /**
  718. * We can't just use ancestry roots, because PhpGtkException is not a root,
  719. * and other similar cases might arise in later versions.
  720. */
  721. if (count(array_intersect(self::getClassAncestry($className), $phpGtkRoots)))
  722. {
  723. $ret[] = $className;
  724. }
  725. }
  726. return $ret;
  727. }
  728. /**
  729. * List the interfaces in PHP-GTK
  730. *
  731. * Regrettably, the Reflection information on PHP-GTK2 classes
  732. * is incomplete: it does not return the extension information on
  733. * ReflectionClass::getExtension() and ReflectionClass::getExtensionName()
  734. * so we have to use hard-coded information
  735. *
  736. * @return array
  737. */
  738. static public function getPhpGtkInterfaceNames()
  739. {
  740. $arInterfaceNames = get_declared_interfaces();
  741. $ret = array();
  742. foreach($arInterfaceNames as $name)
  743. {
  744. if (strpos($name, 'Gtk') === 0) // we only want interfaces with a name starting by "Gtk"
  745. {
  746. $ret[] = $name;
  747. }
  748. }
  749. return $ret;
  750. }
  751. /**
  752. * return the methods clause
  753. *
  754. * if name is not set, return all the methods, otherwise
  755. * just return the info for the designated method
  756. *
  757. * @param string $name
  758. * @return string
  759. */
  760. function getClassMethods($name = NULL)
  761. {
  762. $ret = '';
  763. $arMethods = empty($name)
  764. ? $this->class->getMethods()
  765. : array('name' => $name);
  766. foreach ($arMethods as $oMethod)
  767. {
  768. $method = $this->class->getMethod($oMethod->name);
  769. $modifiers = Reflection::getModifierNames($method->getModifiers());
  770. $dc = $method->getDeclaringClass();
  771. if ($dc->name != $this->name)
  772. {
  773. continue; // skip inherited classes
  774. }
  775. $modifiers = implode (' ', $modifiers) . ' ';
  776. $arParams = $method->getParameters();
  777. $arParamStrings = array();
  778. foreach ($arParams as $oParam)
  779. {
  780. if ($oParam->isOptional())
  781. continue;
  782. // print_r($oParam);
  783. $name = str_replace(' ', '_', $oParam->name);
  784. $isArray = $oParam->isArray();
  785. $allowsNull = $oParam->allowsNull();
  786. $isRef = $oParam->isPassedByReference();
  787. $isOptional = $oParam->isOptional();
  788. $hasDefault = $oParam->isDefaultValueAvailable();
  789. $default = $hasDefault ? $oParam->getDefaultValue() : NULL;
  790. $s = $isArray ? 'array ' : NULL ;
  791. $s .= $isRef ? '&' : '';
  792. $s .= "$$name";
  793. $s .= $isOptional ? '/* optional */' : '';
  794. $s .= $hasDefault ? ' = ' . $default : NULL;
  795. $arParamStrings[] = $s;
  796. // echo $s . PHP_EOL;
  797. }
  798. switch ($oMethod->name)
  799. {
  800. case 'foreach':
  801. $methodName = 'foreach_method';
  802. break;
  803. case 'unset':
  804. $methodName = 'unset_method';
  805. break;
  806. default:
  807. $methodName = $oMethod->name;
  808. }
  809. $params = '(' . (count($arParamStrings) ? implode(', ', $arParamStrings) : NULL) . ')';
  810. $ret .= ' ' . $modifiers . 'function ' . $methodName . $params . " {}\n";
  811. }
  812. return $ret;
  813. }
  814. }
  815. /**
  816. * Global code
  817. */
  818. function main()
  819. {
  820. echo "<?php\n";
  821. echo getExtensionInfo();
  822. foreach (Gtk_Dumper::getPhpGtkInterfaceNames() as $interfaceName)
  823. {
  824. $interface = new GtkReflectionInterface($interfaceName);
  825. echo $interface->asPhp();
  826. }
  827. foreach (Gtk_Dumper::getPhpGtkClassNames() as $className)
  828. {
  829. $class = new GtkReflectionClass($className);
  830. echo $class->asPhp();
  831. }
  832. }
  833. main();