changed git call from https to git readonly
[atutor.git] / mods / phpdoc2 / PhpDocumentor / phpDocumentor / Classes.inc
1 <?php\r
2 /**\r
3  * Intermediate class parsing structure.\r
4  *\r
5  * phpDocumentor :: automatic documentation generator\r
6  * \r
7  * PHP versions 4 and 5\r
8  *\r
9  * Copyright (c) 2001-2007 Gregory Beaver\r
10  * \r
11  * LICENSE:\r
12  * \r
13  * This library is free software; you can redistribute it\r
14  * and/or modify it under the terms of the GNU Lesser General\r
15  * Public License as published by the Free Software Foundation;\r
16  * either version 2.1 of the License, or (at your option) any\r
17  * later version.\r
18  * \r
19  * This library is distributed in the hope that it will be useful,\r
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
22  * Lesser General Public License for more details.\r
23  * \r
24  * You should have received a copy of the GNU Lesser General Public\r
25  * License along with this library; if not, write to the Free Software\r
26  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
27  *\r
28  * @category  ToolsAndUtilities\r
29  * @package   phpDocumentor\r
30  * @author    Greg Beaver <cellog@php.net>\r
31  * @copyright 2001-2007 Gregory Beaver\r
32  * @license   http://www.opensource.org/licenses/lgpl-license.php LGPL\r
33  * @version   CVS: $Id: Classes.inc,v 1.11 2007/10/10 01:18:25 ashnazg Exp $\r
34  * @filesource\r
35  * @link      http://www.phpdoc.org\r
36  * @link      http://pear.php.net/PhpDocumentor\r
37  * @see       parserDocBlock, parserInclude, parserPage, parserClass\r
38  * @see       parserDefine, parserFunction, parserMethod, parserVar\r
39  * @since     1.0rc1\r
40  * @todo      CS cleanup - change package to PhpDocumentor\r
41  */\r
42 /**\r
43  * Intermediate class parsing structure.\r
44  *\r
45  * The {@link phpDocumentor_IntermediateParser} class uses this class and its\r
46  * cousin, {@link ProceduralPages} to organize all parsed source code elements.\r
47  * Data is fed to each immediately after it is parsed, and at conversion time,\r
48  * everything is organized.\r
49  *\r
50  * The Classes class is responsible for all inheritance, including resolving\r
51  * name conflicts between classes, determining which classes extend other\r
52  * classes, and is responsible for all inheritance of documentation.\r
53  * {@internal\r
54  * This structure parses classes, vars and methods by file, and then iterates\r
55  * over the class tree to set up inheritance.  The {@link Inherit()}\r
56  * method is the meat of the class, and processes the class trees from root to\r
57  * branch, ensuring that parsing order is unimportant.}}\r
58  *\r
59  * @category  ToolsAndUtilities\r
60  * @package   phpDocumentor\r
61  * @author    Greg Beaver <cellog@php.net>\r
62  * @copyright 2001-2007 Gregory Beaver\r
63  * @license   http://www.opensource.org/licenses/lgpl-license.php LGPL\r
64  * @version   Release: 1.4.1\r
65  * @link      http://www.phpdoc.org\r
66  * @link      http://pear.php.net/PhpDocumentor\r
67  * @since     1.0rc1\r
68  * @todo      CS cleanup - change package to PhpDocumentor\r
69  */\r
70 class Classes\r
71 {\r
72     /**#@+\r
73      * @access private\r
74      */\r
75     /**\r
76      * file being parsed, used in every add function to match up elements with \r
77      * the file that contains them\r
78      *\r
79      * This variable is used during parsing to associate class elements added\r
80      * to the data structures that contain them with the file they reside in\r
81      * @see addClass(), addMethod(), addVar(), nextFile()\r
82      * @var string\r
83      */\r
84     var $curfile;\r
85     /**\r
86      * class being parsed, used to match up methods and vars with their parent\r
87      * class\r
88      *\r
89      * This variable is used during parsing to associate class elements added\r
90      * to the data structures that contain them with the file they reside in\r
91      * @see addMethod(), addVar()\r
92      * @var string\r
93      */\r
94     var $curclass;\r
95     \r
96     /**\r
97      * Used when a definite match is made between a parent class and a child\r
98      * class\r
99      *\r
100      * This variable is used in post-parsing.\r
101      *\r
102      * Format:<pre>\r
103      * array(\r
104      *     parent => array(\r
105      *         parentfile => array(\r
106      *             child => childfile\r
107      *         )\r
108      *     )\r
109      * )</pre>\r
110      * @var array\r
111      */\r
112     var $definitechild;\r
113     /**\r
114      * array of parsed classes organized by the name of the file that contains\r
115      * the class.\r
116      *\r
117      * Format:<pre>\r
118      * array(\r
119      *     filename => array(\r
120      *         classname => {@link parserClass}\r
121      *     )\r
122      * )</pre>\r
123      * @var array\r
124      */\r
125     var $classesbyfile = array();\r
126     /**\r
127      * array of file names organized by classes that are in the file.\r
128      *\r
129      * This structure is designed to handle name conflicts.  Two files can\r
130      * contain classes with the same name, and this array will record both\r
131      * filenames to help control linking and inheritance errors\r
132      *\r
133      * Format:<pre>\r
134      * array(\r
135      *     classname => array(\r
136      *         name of file containing classname,\r
137      *         name of file 2 containing classname,\r
138      *         ...\r
139      *     )\r
140      * )</pre>\r
141      * @var array\r
142      */\r
143     var $classesbynamefile = array();\r
144     /**\r
145      * array of parsed methods organized by the file that contains them.\r
146      *\r
147      * Format:<pre>\r
148      * array(\r
149      *     filename => array(\r
150      *         classname => array(\r
151      *             {@link parserMethod} 1, \r
152      *             {@link parserMethod} 2,\r
153      *             ...\r
154      *         )\r
155      *     )\r
156      * )</pre>\r
157      * @var array\r
158      */\r
159     var $methodsbyfile = array();\r
160     /**\r
161      * array of parsed vars organized by the file that contains them.\r
162      *\r
163      * Format:<pre>\r
164      * array(\r
165      *     filename => array(\r
166      *         classname => array(\r
167      *             {@link parserVar} 1, \r
168      *             {@link parserVar} 2,\r
169      *             ...\r
170      *         )\r
171      *     )\r
172      * )</pre>\r
173      * @var array\r
174      */\r
175     var $varsbyfile = array();\r
176     /**\r
177      * array of parsed class constants organized by the file that contains them.\r
178      *\r
179      * Format:<pre>\r
180      * array(\r
181      *     filename => array(\r
182      *         classname => array(\r
183      *             {@link parserConst} 1, \r
184      *             {@link parserConst} 2,\r
185      *             ...\r
186      *         )\r
187      *     )\r
188      * )</pre>\r
189      * @var array\r
190      */\r
191     var $constsbyfile = array();\r
192     /**\r
193      * keeps track of extend declarations by file, used to find inheritance\r
194      *\r
195      * Format:<pre>\r
196      * array(\r
197      *     filename => array(\r
198      *         classname => parentclassname\r
199      *     )\r
200      * )</pre>\r
201      * @var array\r
202      */\r
203     var $extendsbyfile = array();\r
204     /**\r
205      * Keeps track of child classes by file.\r
206      * Since phpDocumentor can document collections of files that contain name\r
207      * conflicts (PHP would give a fatal error), it\r
208      * is impossible to assume a class that declares "extends foo" necessarily\r
209      * extends the class foo in file X.  It could be an\r
210      * extended class of class foo in file Y.  Because of this, phpDocumentor\r
211      * relies on packaging to resolve the name conflict\r
212      * This array keeps track of the packages of a child class\r
213      *\r
214      * Format:<pre>\r
215      * array(\r
216      *     parentclassname => array(\r
217      *         filename => array(\r
218      *             childclassname => array(\r
219      *                 packagename, \r
220      *                 packagename\r
221      *             )\r
222      *         )\r
223      *     )\r
224      * )</pre>\r
225      * @var array\r
226      */\r
227     var $classchildrenbyfile = array();\r
228     /**\r
229      * Keeps track of class packages found in a file.\r
230      * This is used in {@link getParentClass()} to determine the number of\r
231      * packages in a file, in order to resolve inheritance issues\r
232      * Format:<pre>\r
233      * array(\r
234      *     filename => array(\r
235      *         packagename1, \r
236      *         packagename2,\r
237      *         ...\r
238      *     )\r
239      * )</pre>\r
240      * @var array\r
241      */\r
242     var $classpackagebyfile = array();\r
243     /**\r
244      * a tree of class inheritance by name.\r
245      *\r
246      * Format:<pre>\r
247      * array(\r
248      *     childname => parentname,\r
249      *     childname1 => parentname1,\r
250      *     rootname => 0, \r
251      *     ...\r
252      * )</pre>\r
253      * @var array\r
254      * @see Converter::generateSortedClassTreeFromClass()\r
255      */\r
256     var $classparents = array();\r
257     /**\r
258      * Keeps track of package and subpackage for each class name, organized\r
259      * by package\r
260      *\r
261      * Format:<pre>\r
262      * array(\r
263      *     classname => array(\r
264      *         path => array(\r
265      *             package,\r
266      *             subpackage\r
267      *         ),\r
268      *         path2 => array(\r
269      *             package,\r
270      *             subpackage\r
271      *         ),\r
272      *         ...\r
273      *     )\r
274      * )</pre>\r
275      * @var array\r
276      */\r
277     var $classpathpackages = array();\r
278     /**\r
279      * used to delete duplicates in the same package to avoid documentation errors\r
280      *\r
281      * Specifically used in {@link Converter::checkKillClass()}\r
282      */\r
283     var $killclass = array();\r
284     /**\r
285      * array of methods by package and class\r
286      *\r
287      * format:<pre>\r
288      * array(packagename =>\r
289      *         array(classname =>\r
290      *               array(methodname1 => {@link parserMethod} class,\r
291      *                     methodname2 => {@link parserMethod} class,...)\r
292      *                      )\r
293      *              )\r
294      *      )</pre>\r
295      * @var array\r
296      * @see Converter\r
297      */\r
298     var $methods = array();\r
299     \r
300     /**\r
301      * array of class variables by package and class\r
302      *\r
303      * format:<pre>\r
304      * array(packagename =>\r
305      *         array(classname =>\r
306      *                array(variablename1 => {@link parserVar} class,\r
307      *                      variablename2 => {@link parserVar} class,...\r
308      *                     )\r
309      *              )\r
310      *      )</pre>\r
311      * @var array\r
312      * @see Converter\r
313      */\r
314     var $vars = array();\r
315     \r
316     /**\r
317      * array of class variables by package and class\r
318      *\r
319      * format:<pre>\r
320      * array(packagename =>\r
321      *         array(classname =>\r
322      *                array(constname1 => {@link parserConst} class,\r
323      *                      constname2 => {@link parserConst} class,...\r
324      *                     )\r
325      *              )\r
326      *      )</pre>\r
327      * @var array\r
328      * @see Converter\r
329      */\r
330     var $consts = array();\r
331     /**\r
332      * Reverse class_packages_by_file, used to prevent duplicates\r
333      * @var array Format: array(packagename => 1)\r
334      */\r
335     var $revcpbf = array();\r
336     /**\r
337      * All classes with no parents (no extends clause) are tracked in this array\r
338      * by the file that contains them.\r
339      *\r
340      * Format:<pre>\r
341      * array(\r
342      *     classname => array(\r
343      *         name of file1 that contains root classname,\r
344      *         name of file2 that contains root classname,\r
345      *         ...\r
346      *     )\r
347      * )</pre>\r
348      * @var array\r
349      */\r
350     var $roots = array();\r
351     /**\r
352      * All classes with a parent that was not parsed are included in this array\r
353      *\r
354      * Format:<pre>\r
355      * array(\r
356      *     classname => array(\r
357      *         name of file1 that contains root classname,\r
358      *         name of file2 that contains root classname,\r
359      *         ...\r
360      *     )\r
361      * )</pre>\r
362      * @var array\r
363      */\r
364     var $specialRoots = array();\r
365     \r
366     /**\r
367      * array of all files that contain classes with the same name\r
368      * @var array Format: (classname => array(path1, path2,...))\r
369      */\r
370     var $potentialclassconflicts = array();\r
371     \r
372     /**\r
373      * array of all inter-package name conflicts of classes\r
374      *\r
375      * This array allows documentation of PHP namespace conflicts that would\r
376      * occur should a user try to include these files in the same file\r
377      * @var array Format: (classname => array(path1, path2,...))\r
378      */\r
379     var $classconflicts = array();\r
380     /**#@-*/\r
381     /**\r
382      * While parsing, add a class to the list of parsed classes\r
383      *\r
384      * sets up the {@link $classesbyfile, $classesbynamefile, $extendsbyfile},\r
385      * {@link $classchildrenbyfile, $roots} arrays, and sets {@link $curclass}\r
386      *\r
387      * @param parserClass &$element element is a {@link parserClass}\r
388      *\r
389      * @return void\r
390      * @uses addPackageToFile() marks the current class's package as being\r
391      *                          present in a file\r
392      */\r
393     function addClass(&$element)\r
394     {\r
395         $this->curclass   = $element->getName();\r
396         $element->curfile = $this->curfile;\r
397         if (isset($this->classesbyfile[$this->curfile][$this->curclass])) {\r
398             addWarning(PDERROR_ELEMENT_IGNORED, \r
399                 'class', $this->curclass, $this->curfile);\r
400             $this->curclass = false;\r
401             return;\r
402         }\r
403         $this->\r
404             classesbyfile\r
405                 [$this->curfile][$this->curclass]\r
406             = $element;\r
407         $this->\r
408             classesbynamefile[$this->curclass][]\r
409             = $this->curfile;\r
410         $this->\r
411             extendsbyfile[$this->curfile][$this->curclass]\r
412             = $element->getExtends();\r
413         $this->\r
414             classchildrenbyfile[$element->getExtends()]\r
415                 [$this->curfile][$this->curclass][] \r
416             = $element->docblock->package;\r
417         if ($element->docblock->getExplicitPackage())\r
418         $this->addPackageToFile($element->docblock->package);\r
419         if (!$element->getExtends()) {\r
420             $this->roots[$this->curclass][] = $this->curfile;\r
421         }\r
422     }\r
423     \r
424     /**\r
425      * While parsing, add a method to the list of parsed methods\r
426      *\r
427      * sets up the {@link $methodsbyfile} array using {@link $curfile} and\r
428      * {@link $curclass}\r
429      *\r
430      * @param parserMethod &$element element is a {@link parserMethod}\r
431      *\r
432      * @return void\r
433      */\r
434     function addMethod(&$element)\r
435     {\r
436         if (!$this->curclass) return;\r
437         $this->methodsbyfile[$this->curfile][$this->curclass][] = $element;\r
438     }\r
439     \r
440     /**\r
441      * While parsing, add a variable to the list of parsed variables\r
442      *\r
443      * sets up the {@link $varsbyfile} array using {@link $curfile} \r
444      * and {@link $curclass}\r
445      *\r
446      * @param parserVar &$element element is a {@link parserVar}\r
447      *\r
448      * @return void\r
449      */\r
450     function addVar(&$element)\r
451     {\r
452         if (!$this->curclass) return;\r
453         $this->varsbyfile[$this->curfile][$this->curclass][] = $element;\r
454     }\r
455     \r
456     /**\r
457      * While parsing, add a variable to the list of parsed variables\r
458      *\r
459      * sets up the {@link $constsbyfile} array using {@link $curfile} \r
460      * and {@link $curclass}\r
461      *\r
462      * @param parserConst &$element element is a {@link parserConst}\r
463      *\r
464      * @return void\r
465      */\r
466     function addConst(&$element)\r
467     {\r
468         if (!$this->curclass) return;\r
469         $this->constsbyfile[$this->curfile][$this->curclass][] = $element;\r
470     }\r
471     \r
472     /**\r
473      * Prepare to parse a new file\r
474      *\r
475      * sets {@link $curfile} to $file and {@link $curclass} \r
476      * to false (no class being parsed)\r
477      *\r
478      * @param string $file file currently being parsed\r
479      *\r
480      * @return void\r
481      */\r
482     function nextFile($file)\r
483     {\r
484         $this->curfile  = $file;\r
485         $this->curclass = false;\r
486     }\r
487     \r
488     /**\r
489      * Mark a package as being used in a class\r
490      *\r
491      * {@source}\r
492      *\r
493      * @param string $package package name\r
494      *\r
495      * @return void\r
496      */\r
497     function addPackageToFile($package)\r
498     {\r
499         if (!isset($this->revcpbf[$this->curfile][$package]))\r
500         $this->classpackagebyfile[$this->curfile][] = $package;\r
501         $this->revcpbf[$this->curfile][$package]    = 1;\r
502     }\r
503     \r
504     /**\r
505      * Find the parent class of $class, and set up structures to note this fact\r
506      *\r
507      * Modifies the {@link parserClass} element in {@link $classesbyfile} to use\r
508      * the parent's package, and inherit methods/vars\r
509      *\r
510      * @param string $class child class to find parent class\r
511      * @param string $file  file child class is located in\r
512      *\r
513      * @return void\r
514      * @uses $definitechild if a match is made between a parent class and parameter\r
515      *                      $class in file $file, then definitechild is set here\r
516      * @uses getParentClass() to find the parent class\r
517      */\r
518     function setClassParent($class,$file)\r
519     {\r
520         if (is_array($par = $this->getParentClass($class, $file))) {\r
521             // (for debugging)\r
522             // phpDocumentor_out("$file class $class extends "\r
523             //    . $par[1] ." file ". $par[0] . "\n");\r
524 \r
525             $this->classesbyfile[$file][$class]->setParent($par[1], $par[0], $this);\r
526             $this->definitechild[$par[1]][$par[0]][$class] = $file;\r
527         } else {\r
528             $this->classesbyfile[$file][$class]->setParentNoClass($par);\r
529         }\r
530     }\r
531     \r
532     /**\r
533      * Main processing engine for setting up class inheritance.\r
534      *\r
535      * This function uses {@link $roots} to traverse the inheritance tree via\r
536      * {@link processChild()} and returns the data structures\r
537      * phpDocumentor_IntermediateParser needs to convert parsed data\r
538      * to output using {@link phpDocumentor_IntermediateParser::Convert()}\r
539      *\r
540      * @param phpDocumentor_IntermediateParser &$render the renderer object\r
541      *\r
542      * @return void\r
543      * @uses processChild() set up inheritance\r
544      * @todo CS Cleanup - rename to "inherit" for CamelCaps naming standard\r
545      */\r
546     function Inherit(&$render)\r
547     {\r
548         phpDocumentor_out("\nProcessing Class Inheritance\n\n");\r
549         flush();\r
550         phpDocumentor_out("\nProcessing Root Trees\n\n");\r
551         flush();\r
552         foreach ($this->roots as $class => $files) {\r
553             for ($i=0; $i<count($files); $i++) {\r
554                 $this->processChild($render, $class, $files[$i]);\r
555             }\r
556         }\r
557         if (0)\r
558         foreach ($this->classesbyfile as $i => $j) {\r
559             foreach ($j as $k => $m) {\r
560                 var_dump($i, $k);\r
561                 if ($i == 'iConverter') {\r
562                     var_dump($j);\r
563                 }\r
564             }\r
565         }\r
566         phpDocumentor_out("\nProcessing leftover classes "\r
567             . "(classes that extend root classes not found in the same package)\n");\r
568         flush();\r
569         foreach ($this->classesbyfile as $i => $j) {\r
570             foreach ($j as $k => $m) {\r
571                 $this->processChild($render, $k, $i, true);\r
572             }\r
573         }\r
574         phpDocumentor_out("done processing leftover classes\n");\r
575         flush();\r
576         $this->setupClassConflicts();\r
577     }\r
578     \r
579     /**\r
580      * Transfers actual conflicts from {@link $potentialClassconflicts} to\r
581      * {@link $classconflicts}\r
582      *\r
583      * @return void\r
584      * @access private\r
585      * @uses $potentialclassconflicts transfers values to {@link $classconflicts}\r
586      */\r
587     function setupClassConflicts()\r
588     {\r
589         foreach ($this->potentialclassconflicts as $class => $paths) {\r
590             if (count($paths) - 1) { //conflict\r
591                 $package = array();\r
592                 foreach ($paths as $path) {\r
593                     // create a list of conflicting classes in each package\r
594                     if (isset($this->classpathpackages[$class][$path]))\r
595                     $package[$this->classpathpackages[$class][$path][0]][] = $path;\r
596                 }\r
597                 foreach ($package as $pathpackages) {\r
598                     /*\r
599                      * if at least 2 functions exist in the same package, \r
600                      * delete all but the first one and add warnings\r
601                      */\r
602                     if (count($pathpackages) - 1) {\r
603                         for ($i=1; $i < count($pathpackages); $i++) {\r
604                             if (isset($this->classesbyfile[$pathpackages[$i]])) {\r
605                                 addWarning(PDERROR_ELEMENT_IGNORED, \r
606                                     'class', $class, $pathpackages[$i]);\r
607                                 $this->killClass($class, $pathpackages[$i]);\r
608                                 $oth = array_flip($paths);\r
609                                 unset($paths[$oth[$pathpackages[$i]]]);\r
610                             }\r
611                         }\r
612                     }\r
613                 }\r
614                 $this->classconflicts[$class] = $paths;\r
615             }\r
616         }\r
617     }\r
618     \r
619     /**\r
620      * If a package contains two classes with the same name, this function finds\r
621      * that conflict\r
622      *\r
623      * Returns the {@link $classconflicts} entry for class $class, minus its own path\r
624      *\r
625      * @param mixed $class the class name to search for\r
626      *\r
627      * @return mixed returns false if no conflicts, \r
628      *               or an array of paths containing conflicts\r
629      */\r
630     function getConflicts($class)\r
631     {\r
632         if (!isset($this->classconflicts[$class])) return false;\r
633         $a = array();\r
634         foreach ($this->classconflicts[$class] as $conflict) {\r
635             $a[$this->classesbyfile[$conflict][$class]->docblock->package] \r
636                 = $this->classesbyfile[$conflict][$class];\r
637         }\r
638         return $a;\r
639     }\r
640     \r
641     /**\r
642      * sets up {@link $killclass} for use by Converter::checkKillClass()\r
643      *\r
644      * @param mixed $class the class\r
645      * @param mixed $path  the path\r
646      *\r
647      * @return void\r
648      * @access private\r
649      */\r
650     function killClass($class,$path)\r
651     {\r
652         $this->killclass[$class][$path] = true;\r
653     }\r
654     \r
655     /**\r
656      * This function recursively climbs up the class tree, setting inherited\r
657      * information like package and adds the elements to \r
658      * {@link phpDocumentor_IntermediateParser}.\r
659      *\r
660      * Using structures defined in {@link Classes}, \r
661      * the function first sets package information,\r
662      * and then seeks out child classes.\r
663      * It uses 3 tests to determine whether a class is a child class.\r
664      * <ol>\r
665      *    <li>child class is in the same file as the parent class \r
666      *        and extends parent class\r
667      *    </li>\r
668      *    <li>child class is in a different file and specifies \r
669      *        the parent's @package in its docblock\r
670      *    </li>\r
671      *    <li>child class is in a different file and is in a \r
672      *        different @package, with one possible parent class\r
673      *    </li>\r
674      * </ol>\r
675      *\r
676      * @param phpDocumentor_IntermediateParser &$render the renderer object\r
677      * @param string                           $class   class to process\r
678      * @param string                           $file    name of file $class \r
679      *                                                  is located in\r
680      * @param boolean                          $furb    flag used privately\r
681      *                                                  to control informational\r
682      *                                                  output while parsing\r
683      *                                                  (used when processing \r
684      *                                                  leftover classes in \r
685      *                                                  {@link Inherit()}\r
686      *\r
687      * @return void\r
688      * @global string default package, usually "default"\r
689      */\r
690     function processChild(&$render,$class,$file,$furb = false)\r
691     {\r
692         global $phpDocumentor_DefaultPackageName;\r
693         if (isset($this->classesbyfile[$file][$class]->processed))\r
694             return;\r
695         $this->potentialclassconflicts[$class][] = $file;\r
696         if ($furb)\r
697             phpDocumentor_out("Processing $class in file $file\n");\r
698         flush();\r
699         $this->classesbyfile[$file][$class]->processed = true;\r
700 \r
701         $db = $this->classesbyfile[$file][$class];\r
702         $render->addUses($db, $file);\r
703         if (!$render->parsePrivate) {\r
704             /*\r
705              * if this class has an @access private, \r
706              * and parse private is disabled, remove it\r
707              */\r
708             if ($db->docblock->hasaccess) {\r
709                 $aaa = $db->docblock->getKeyword('access');\r
710                 if (is_object($aaa) && $aaa->getString() == 'private') {\r
711                     if (isset($this->varsbyfile[$file]) \r
712                         && isset($this->varsbyfile[$file][$class])) {\r
713                         unset($this->varsbyfile[$file][$class]);\r
714                     }\r
715                     if (isset($this->methodsbyfile[$file]) \r
716                         && isset($this->methodsbyfile[$file][$class])) {\r
717                         unset($this->methodsbyfile[$file][$class]);\r
718                     }\r
719                     if (isset($this->constsbyfile[$file]) \r
720                         && isset($this->constsbyfile[$file][$class])) {\r
721                         unset($this->constsbyfile[$file][$class]);\r
722                     }\r
723                     $this->classesbyfile[$file][$class]->ignore = true;\r
724                     // if this is a root class, remove it from the roots array\r
725                     if (isset($this->roots[$class])) {\r
726                         foreach ($this->roots[$class] as $i => $files) {\r
727                             // find the file key and unset\r
728                             if ($files == $file) \r
729                                 unset($this->roots[$class][$i]);\r
730                         }\r
731                     }\r
732                     /*\r
733                      * if this is a child, remove it from the list \r
734                      * of child classes of its parent\r
735                      */\r
736                     if ($db->getExtends()) \r
737                         unset($this->classchildrenbyfile[$db->getExtends()][$file]);\r
738                     return;\r
739                 }\r
740             }\r
741         }\r
742         if ($render->packageoutput) {\r
743             if (!in_array($db->docblock->package, $render->packageoutput)) {\r
744                 if (isset($this->varsbyfile[$file]) \r
745                     && isset($this->varsbyfile[$file][$class])) {\r
746                     unset($this->varsbyfile[$file][$class]);\r
747                 }\r
748                 if (isset($this->methodsbyfile[$file]) \r
749                     && isset($this->methodsbyfile[$file][$class])) {\r
750                     unset($this->methodsbyfile[$file][$class]);\r
751                 }\r
752                 if (isset($this->constsbyfile[$file]) \r
753                     && isset($this->constsbyfile[$file][$class])) {\r
754                     unset($this->constsbyfile[$file][$class]);\r
755                 }\r
756                 $this->classesbyfile[$file][$class]->ignore = true;\r
757                 if (isset($this->roots[$class])) {\r
758                     foreach ($this->roots[$class] as $i => $files) {\r
759                         if ($files == $file) unset($this->roots[$class][$i]);\r
760                     }\r
761                 }\r
762                 if ($db->getExtends()) \r
763                     unset($this->classchildrenbyfile[$db->getExtends()][$file]);\r
764                 return;\r
765             }\r
766         }\r
767         $this->setClassParent($class, $file);\r
768         $db = $this->classesbyfile[$file][$class];\r
769         if ($furb && !is_array($db->parent)) {\r
770             // debug("furb adding $class $file to roots");\r
771             $this->specialRoots[$db->parent][] = array($class, $file);\r
772         }\r
773         // fix for 591396\r
774         if (!$db->docblock->getExplicitPackage()) {\r
775             $a = $render->proceduralpages->pagepackages[$file];\r
776             if ($a[0] != $phpDocumentor_DefaultPackageName) {\r
777                 // inherit page package\r
778                 $this->classesbyfile[$file][$class]->docblock->package = $a[0];\r
779             }\r
780         }\r
781         if ($this->classesbyfile[$file][$class]->docblock->package \r
782             == $render->proceduralpages->pagepackages[$file][0]) {\r
783             if ($this->classesbyfile[$file][$class]->docblock->subpackage == '') {\r
784                 $this->classesbyfile[$file][$class]->docblock->subpackage \r
785                     = $render->proceduralpages->pagepackages[$file][1];\r
786             }\r
787         }\r
788         $db = $this->classesbyfile[$file][$class];\r
789         $render->addPackageParent($db);\r
790         $render->addPageIfNecessary($file, $db);\r
791         if ($access = $db->docblock->getKeyword('access')) {\r
792             if (!is_string($access) && is_object($access)) \r
793                 $access = $access->getString();\r
794             if (!is_string($access)) \r
795                 $access = 'public';\r
796             if (($access == 'private') && (!$render->parsePrivate)) {\r
797                 if (isset($this->varsbyfile[$file]) \r
798                     && isset($this->varsbyfile[$file][$class])) {\r
799                     foreach ($this->varsbyfile[$file][$class] as $i => $vr) {\r
800                         $vr->docblock->addKeyword('access', 'private');\r
801                         $this->varsbyfile[$file][$class][$i] = $vr;\r
802                     }\r
803                 }\r
804                 if (isset($this->methodsbyfile[$file]) \r
805                     && isset($this->methodsbyfile[$file][$class])) {\r
806                     foreach ($this->methodsbyfile[$file][$class] as $i => $vr) {\r
807                         $vr->docblock->addKeyword('access', 'private');\r
808                         $this->methodsbyfile[$file][$class][$i] = $vr;\r
809                     }\r
810                 }\r
811                 if (isset($this->constsbyfile[$file]) \r
812                     && isset($this->constsbyfile[$file][$class])) {\r
813                     foreach ($this->constsbyfile[$file][$class] as $i => $vr) {\r
814                         $vr->docblock->addKeyword('access', 'private');\r
815                         $this->constsbyfile[$file][$class][$i] = $vr;\r
816                     }\r
817                 }\r
818             }\r
819         }\r
820         $this->classpathpackages[$class][$file] \r
821             = array($db->docblock->package,$db->docblock->subpackage);\r
822         if ($db->docblock->getExplicitPackage()) {\r
823             $render->proceduralpages->\r
824                 addClassPackageToFile($file, \r
825                     $db->docblock->package, $db->docblock->subpackage);\r
826         }\r
827         $render->addElementToPage($db, $file);\r
828         if (isset($this->varsbyfile[$file]) \r
829             && isset($this->varsbyfile[$file][$class])) {\r
830             foreach ($this->varsbyfile[$file][$class] as $i => $vr) {\r
831                 $vr->docblock->package    = $db->docblock->package;\r
832                 $vr->docblock->subpackage = $db->docblock->subpackage;\r
833                 $render->addElementToPage($vr, $file);\r
834                 $render->addUses($vr, $file);\r
835                 $this->varsbyfile[$file][$class][$i]                        = $vr;\r
836                 $this->vars[$db->docblock->package][$class][$vr->getName()] = $vr;\r
837             }\r
838         }\r
839         if (isset($this->methodsbyfile[$file]) \r
840             && isset($this->methodsbyfile[$file][$class])) {\r
841             foreach ($this->methodsbyfile[$file][$class] as $i => $vr) {\r
842                 $vr->docblock->package    = $db->docblock->package;\r
843                 $vr->docblock->subpackage = $db->docblock->subpackage;\r
844                 $render->addElementToPage($vr, $file);\r
845                 $render->addUses($vr, $file);\r
846                 $this->methodsbyfile[$file][$class][$i]                        = $vr;\r
847                 $this->methods[$db->docblock->package][$class][$vr->getName()] = $vr;\r
848             }\r
849         }\r
850         if (isset($this->constsbyfile[$file]) \r
851             && isset($this->constsbyfile[$file][$class])) {\r
852             foreach ($this->constsbyfile[$file][$class] as $i => $vr) {\r
853                 $vr->docblock->package    = $db->docblock->package;\r
854                 $vr->docblock->subpackage = $db->docblock->subpackage;\r
855                 $render->addElementToPage($vr, $file);\r
856                 $render->addUses($vr, $file);\r
857                 $this->constsbyfile[$file][$class][$i]                         = $vr;\r
858                 $this->methods[$db->docblock->package][$class][$vr->getName()] = $vr;\r
859             }\r
860         }\r
861         $this->classpackages[$class][] \r
862             = array($db->docblock->package,$db->docblock->subpackage);\r
863         if (is_array($db->parent))\r
864             $this->classparents[$db->docblock->package][$class] = $db->parent[1];\r
865         else\r
866             $this->classparents[$db->docblock->package][$class] = $db->getExtends();\r
867         if (is_array($db->parent)) {\r
868             $z = $this->getClass($db->parent[1], $db->parent[0]);\r
869 \r
870             $this->classchildren[$z->docblock->package][$db->parent[1]][] = $db;\r
871         }\r
872         if (isset($this->classchildrenbyfile[$class])) {\r
873             foreach ($this->classchildrenbyfile[$class] as $childfile => $other) {\r
874                 // test 1, inherits in same file (must be same package)\r
875                 if ($childfile == $file) {\r
876                     foreach ($other as $child => $packages) {\r
877                         // debug("parent $class same file $child");\r
878                         $this->processChild($render, $child, $childfile);\r
879                         $x = $this->getClass($child, $childfile);\r
880                         if ($x->docblock->package \r
881                             != $GLOBALS['phpDocumentor_DefaultPackageName']) {\r
882                             // child package need root for class trees\r
883                             if ($x->docblock->package != $db->docblock->package) {\r
884                                 // debug("adding $child in $childfile 1");\r
885                                 $this->roots[$child][] = $childfile;\r
886                             }\r
887                         }\r
888                     }\r
889                 } else {\r
890                     // test 2, different file, same package\r
891                     foreach ($other as $child => $packages) {\r
892                         for ($j=0; $j<count($packages); $j++) {\r
893                             if ($this->classesbyfile[$file][$class]->\r
894                                     docblock->package == $packages[$j]) {\r
895                                 $this->processChild($render, $child, $childfile);\r
896                                 // debug("$childfile diff file $child, parent $class,\r
897                                 //     same package ".$packages[$j]);\r
898                             } else {\r
899                                 /*\r
900                                  * test 3, different file, different package, \r
901                                  * only 1 parent is possible\r
902                                  */\r
903                                 if (isset($this->classesbynamefile[$child])) {\r
904                                     // 1 possible parent\r
905                                     if (count($this->classesbynamefile[$class]) \r
906                                         == 1) {\r
907                                         // debug("$childfile diff file $child, \r
908                                         //        diff package, \r
909                                         //        1 possible parent root $class");\r
910                                         $this->processChild($render, \r
911                                             $child, $childfile);\r
912                                         $x = $this->getClass($child, $childfile);\r
913                                         if ($x->docblock->package \r
914                                           != $GLOBALS\r
915                                           ['phpDocumentor_DefaultPackageName']) {\r
916                                             // child package need root \r
917                                             //for class trees\r
918                                             if ($x->docblock->package \r
919                                                 != $db->docblock->package) {\r
920                                                 // debug("adding roots \r
921                                                 // $child in $childfile 2");\r
922                                                 $this->roots[$child][] = $childfile;\r
923                                             }\r
924                                         }\r
925                                     }\r
926                                 }\r
927                             }\r
928                         }\r
929                     }\r
930                 }\r
931             }\r
932         }\r
933     }\r
934     \r
935     /**\r
936      * Get the parserClass representation of a class from its name and file\r
937      *\r
938      * @param string $class classname\r
939      * @param string $file  file classname is located in\r
940      *\r
941      * @return parserClass\r
942      */\r
943     function &getClass($class, $file)\r
944     {\r
945         // debug("getClass called with class $class file $file");\r
946         return $this->classesbyfile[$file][$class];\r
947     }\r
948     \r
949     /**\r
950      * Used by {@link parserData::getClasses()} \r
951      * to retrieve classes defined in file $path\r
952      *\r
953      * retrieves the array entry from {@link $classesbyfile} for $path\r
954      *\r
955      * @param string $path full path to filename\r
956      *\r
957      * @return mixed returns false if no classes defined in the file, \r
958      *               otherwise returns an array of {@link parserClass}es\r
959      */\r
960     function getClassesInPath($path)\r
961     {\r
962         if (!isset($this->classesbyfile[$path])) return false;\r
963         return $this->classesbyfile[$path];\r
964     }\r
965     \r
966     /**\r
967      * called by {@link parserClass::hasMethods()}.  Should not be directly called\r
968      *\r
969      * @param string $file  file classname is located in\r
970      * @param string $class classname\r
971      *\r
972      * @return bool\r
973      * @access private\r
974      */\r
975     function hasMethods($file, $class)\r
976     {\r
977         return isset($this->methodsbyfile[$file][$class]);\r
978     }\r
979     \r
980     /**\r
981      * called by {@link parserClass::hasConsts()}.  \r
982      * Should not be directly called\r
983      *\r
984      * @param string $file  file classname is located in\r
985      * @param string $class classname\r
986      *\r
987      * @return bool\r
988      * @access private\r
989      */\r
990     function hasConsts($file,$class)\r
991     {\r
992         return isset($this->constsbyfile[$file][$class]);\r
993     }\r
994     \r
995     /**\r
996      * called by {@link parserClass::hasVars()}.  Should not be directly called\r
997      *\r
998      * @param string $file  file classname is located in\r
999      * @param string $class classname\r
1000      *\r
1001      * @return bool\r
1002      * @access private\r
1003      */\r
1004     function hasVars($file, $class)\r
1005     {\r
1006         return isset($this->varsbyfile[$file][$class]);\r
1007     }\r
1008     \r
1009     /**\r
1010      * called by {@link parserClass::hasMethod()}.  Should not be directly called\r
1011      *\r
1012      * @param string $class classname\r
1013      * @param string $file  file classname is located in\r
1014      * @param string $name  method name\r
1015      *\r
1016      * @return bool\r
1017      * @access private\r
1018      */\r
1019     function hasMethod($class, $file, $name)\r
1020     {\r
1021         if (!$this->hasMethods($file, $class)) return false;\r
1022         for ($i=0; $i<count($this->methodsbyfile[$file][$class]); $i++) {\r
1023             if ($this->methodsbyfile[$file][$class][$i]->getName() == $name) \r
1024                return true;\r
1025         }\r
1026         return false;\r
1027     }\r
1028     \r
1029     /**\r
1030      * called by {@link parserClass::hasVar()}.  Should not be directly called\r
1031      *\r
1032      * @param string $class classname\r
1033      * @param string $file  file classname is located in\r
1034      * @param string $name  var name\r
1035      *\r
1036      * @return bool\r
1037      * @access private\r
1038      */\r
1039     function hasVar($class, $file, $name)\r
1040     {\r
1041         if (!$this->hasVars($file, $class)) return false;\r
1042         for ($i=0; $i<count($this->varsbyfile[$file][$class]); $i++) {\r
1043             if ($this->varsbyfile[$file][$class][$i]->getName() == $name) \r
1044                 return true;\r
1045         }\r
1046         return false;\r
1047     }\r
1048     \r
1049     /**\r
1050      * called by {@link parserClass::hasConst()}.  Should not be directly called\r
1051      *\r
1052      * @param string $class classname\r
1053      * @param string $file  file classname is located in\r
1054      * @param string $name  constant name\r
1055      *\r
1056      * @return bool\r
1057      * @access private\r
1058      */\r
1059     function hasConst($class, $file, $name)\r
1060     {\r
1061         if (!$this->hasConsts($file, $class)) return false;\r
1062         for ($i=0; $i<count($this->constsbyfile[$file][$class]); $i++) {\r
1063             if ($this->constsbyfile[$file][$class][$i]->getName() == $name) \r
1064                 return true;\r
1065         }\r
1066         return false;\r
1067     }\r
1068     \r
1069     /**\r
1070      * called by {@link parserClass::getMethods()}.  Should not be directly called\r
1071      *\r
1072      * @param string $class classname\r
1073      * @param string $file  file classname is located in\r
1074      *\r
1075      * @return mixed\r
1076      * @access private\r
1077      */\r
1078     function &getMethods($class, $file)\r
1079     {\r
1080         if (!isset($this->methodsbyfile[$file][$class])) {\r
1081             $flag = false;\r
1082             return $flag;\r
1083         }\r
1084         return $this->methodsbyfile[$file][$class];\r
1085     }\r
1086     \r
1087     /**\r
1088      * called by {@link parserClass::getVars()}.  Should not be directly called\r
1089      *\r
1090      * @param string $class classname\r
1091      * @param string $file  file classname is located in\r
1092      *\r
1093      * @return mixed\r
1094      * @access private\r
1095      */\r
1096     function &getVars($class, $file)\r
1097     {\r
1098         if (!isset($this->varsbyfile[$file][$class])) {\r
1099             $flag = false;\r
1100             return $flag;\r
1101         }\r
1102         return $this->varsbyfile[$file][$class];\r
1103     }\r
1104     \r
1105     /**\r
1106      * called by {@link parserClass::getConsts()}.  Should not be directly called\r
1107      *\r
1108      * @param string $class classname\r
1109      * @param string $file  file classname is located in\r
1110      *\r
1111      * @return mixed\r
1112      * @access private\r
1113      */\r
1114     function &getConsts($class, $file)\r
1115     {\r
1116         if (!isset($this->constsbyfile[$file][$class])) {\r
1117             $flag = false;\r
1118             return $flag;\r
1119         }\r
1120         return $this->constsbyfile[$file][$class];\r
1121     }\r
1122     \r
1123     /**\r
1124      * called by {@link parserClass::getMethod()}.  Should not be directly called\r
1125      *\r
1126      * @param string $class classname\r
1127      * @param string $file  file classname is located in\r
1128      * @param string $name  method name\r
1129      *\r
1130      * @return mixed\r
1131      * @access private\r
1132      */\r
1133     function getMethod($class, $file, $name)\r
1134     {\r
1135         if (!$this->hasMethod($class, $file, $name)) return false;\r
1136         for ($i=0; $i<count($this->methodsbyfile[$file][$class]); $i++) {\r
1137             if ($this->methodsbyfile[$file][$class][$i]->getName() == $name) \r
1138                 return $this->methodsbyfile[$file][$class][$i];\r
1139         }\r
1140     }\r
1141     \r
1142     /**\r
1143      * called by {@link parserClass::getVar()}.  Should not be directly called\r
1144      *\r
1145      * @param string $class classname\r
1146      * @param string $file  file classname is located in\r
1147      * @param string $name  var name\r
1148      *\r
1149      * @return mixed\r
1150      * @access private\r
1151      */\r
1152     function getVar($class, $file, $name)\r
1153     {\r
1154         if (!$this->hasVar($class, $file, $name)) return false;\r
1155         for ($i=0; $i<count($this->varsbyfile[$file][$class]); $i++) {\r
1156             if ($this->varsbyfile[$file][$class][$i]->getName() == $name) \r
1157                 return $this->varsbyfile[$file][$class][$i];\r
1158         }\r
1159     }\r
1160     \r
1161     /**\r
1162      * called by {@link parserClass::getConst()}.  Should not be directly called\r
1163      *\r
1164      * @param string $class classname\r
1165      * @param string $file  file classname is located in\r
1166      * @param string $name  const name\r
1167      *\r
1168      * @return mixed\r
1169      * @access private\r
1170      */\r
1171     function getConst($class, $file, $name)\r
1172     {\r
1173         if (!$this->hasConst($class, $file, $name)) return false;\r
1174         for ($i=0; $i<count($this->constsbyfile[$file][$class]); $i++) {\r
1175             if ($this->constsbyfile[$file][$class][$i]->getName() == $name) \r
1176                 return $this->constsbyfile[$file][$class][$i];\r
1177         }\r
1178     }\r
1179     \r
1180     /**\r
1181      * Search for a class in a package\r
1182      *\r
1183      * @param string $class   classname\r
1184      * @param string $package package classname is in\r
1185      *\r
1186      * @return mixed returns false if no class in $package, \r
1187      *               otherwise returns a {@link parserClass}\r
1188      */\r
1189     function &getClassByPackage($class, $package)\r
1190     {\r
1191         if (!isset($this->classesbynamefile[$class])) {\r
1192             // removed, too many warnings, not very useful\r
1193             // addWarning(PDERROR_CLASS_NOT_IN_PACKAGE,$class,$package); \r
1194 \r
1195             $flag = false;\r
1196             return $flag;\r
1197         }\r
1198         for ($i=0; $i < count($this->classesbynamefile[$class]); $i++) {\r
1199             $cls = \r
1200                 $this->classesbyfile[$this->classesbynamefile[$class][$i]][$class];\r
1201             $pkg = $cls->getPackage();\r
1202             if ($pkg == $package)\r
1203                 return $cls;\r
1204         }\r
1205         // addWarning(PDERROR_CLASS_NOT_IN_PACKAGE,$class,$package);\r
1206 \r
1207         $flag = false;\r
1208         return $flag;\r
1209     }\r
1210     \r
1211     /**\r
1212      * Find the parent class of a class in file $file\r
1213      * uses 3 tests to find the parent classname:\r
1214      * <ol>\r
1215      *    <li>only one class with the parent classname</li>\r
1216      *    <li>more than one class, but only one in the same file as the child</li>\r
1217      *    <li>only one parent class in the same package as the child</li>\r
1218      * </ol>\r
1219      *\r
1220      * @param string $class classname\r
1221      * @param string $file  file classname is located in\r
1222      *\r
1223      * @return mixed false if no parent class, \r
1224      *               a string if no parent class found by that name,\r
1225      *               and an array(file parentclass is in, parentclassname)\r
1226      */\r
1227     function getParentClass($class,$file)\r
1228     {\r
1229         if (!isset($this->classesbyfile[$file][$class])) {\r
1230             return false;\r
1231         }\r
1232         $element = $this->classesbyfile[$file][$class];\r
1233         if (!($ex = $element->getExtends())) return false;\r
1234         // first check to see if there is one and only one \r
1235         // class with the parent class's name\r
1236         if (isset($this->classesbynamefile[$ex])) {\r
1237             if (count($this->classesbynamefile[$ex]) == 1) {\r
1238                 if ($this->classesbyfile\r
1239                     [$this->classesbynamefile[$ex][0]][$ex]->ignore) {\r
1240                     return $ex;\r
1241                 }\r
1242                 return array($this->classesbynamefile[$ex][0],$ex);\r
1243             } else {\r
1244                 // next check to see if there is a parent class in the same file\r
1245                 if (isset($this->classesbyfile[$file][$ex])) {\r
1246                     if ($this->classesbyfile[$file][$ex]->ignore) {\r
1247                         return $ex;\r
1248                     }\r
1249                     return array($file,$ex);\r
1250                 }\r
1251                 // next check to see if there is only one package \r
1252                 // used in the file, try to resolve it that way\r
1253                 if (isset($this->classpackagebyfile[$file])) {\r
1254                     if (count($this->classpackagebyfile[$file]) == 1) {\r
1255                         for ($i=0;$i<count($this->classesbynamefile[$ex]);$i++) {\r
1256                             if ($this->classesbyfile\r
1257                               [$this->classesbynamefile[$ex][$i]][$ex]->getPackage() \r
1258                                == $this->classpackagebyfile[$file][0]) {\r
1259                                 if ($this->classesbyfile\r
1260                                    [$this->classesbynamefile[$ex][$i]][$ex]->ignore) \r
1261                                     return $ex;\r
1262                                 return array($this->classesbynamefile[$ex][$i],$ex);\r
1263                             }\r
1264                         }\r
1265                     }\r
1266                 }\r
1267                 // name conflict\r
1268                 addWarning(PDERROR_INHERITANCE_CONFLICT, $class, $file, $ex);\r
1269                 return $ex;\r
1270             }\r
1271         } else {\r
1272             if (class_exists('ReflectionClass') && class_exists($ex)) {\r
1273                 $r = new ReflectionClass($ex);\r
1274                 if ($r->isInternal()) {\r
1275                     return $ex; // no warning\r
1276                 }\r
1277             }\r
1278             addWarning(PDERROR_PARENT_NOT_FOUND, $class, $ex);\r
1279             return $ex;\r
1280         }\r
1281     }\r
1282     \r
1283     /**\r
1284      * Get a list of all root classes indexed by package.  Used to generate\r
1285      * class trees by {@link Converter}\r
1286      *\r
1287      * @param boolean $all [since phpDocumentor 1.3.0RC6] determines whether to\r
1288      *                     return class trees that extend non-parsed classes\r
1289      *\r
1290      * @return array array(package => array(rootclassname, rootclassname,...),...)\r
1291      */\r
1292     function getRoots($all = false)\r
1293     {\r
1294         $roots     = array();\r
1295         $temproots = $this->roots;\r
1296         if (!$all) {\r
1297             foreach ($this->specialRoots as $package => $root) {\r
1298                 foreach ($root as $parent => $info) {\r
1299                     $temproots[$info[0]][] = $info[1];\r
1300                 }\r
1301             }\r
1302         }\r
1303         foreach ($temproots as $class => $files) {\r
1304             if (count($files)) {\r
1305                 foreach ($files as $i => $boofou) {\r
1306                     $x = $this->getClass($class, $files[$i]);\r
1307 \r
1308                     $roots[$x->getPackage()][] = $class;\r
1309                 }\r
1310             }\r
1311         }\r
1312         foreach ($roots as $package => $root) {\r
1313             usort($roots[$package], "strnatcasecmp");\r
1314         }\r
1315         if ($all) {\r
1316             $specialRoots = array();\r
1317             foreach ($this->specialRoots as $parent => $classinfo) {\r
1318                 if (count($classinfo)) {\r
1319                     foreach ($classinfo as $i => $info) {\r
1320                         $x = $this->getClass($info[0], $info[1]);\r
1321 \r
1322                         $specialRoots[$x->getPackage()][$parent][] = $info[0];\r
1323                     }\r
1324                 }\r
1325             }\r
1326             foreach ($specialRoots as $package => $root) {\r
1327                 uksort($specialRoots[$package], "strnatcasecmp");\r
1328                 foreach ($specialRoots[$package] as $parent => $classes) {\r
1329                     usort($specialRoots[$package][$parent], 'strnatcasecmp');\r
1330                 }\r
1331             }\r
1332             return array('special' => $specialRoots, 'normal' => $roots);\r
1333         }\r
1334         return $roots;\r
1335     }\r
1336     \r
1337     /**\r
1338      * Get all classes confirmed in parsing \r
1339      * to be descended class $parclass in file $file\r
1340      *\r
1341      * @param string $parclass name of parent class\r
1342      * @param string $file     file parent class is found in\r
1343      *\r
1344      * @return mixed either false if no children, or array of format\r
1345      *         array(childname => childfile,childname2 => childfile2,...)\r
1346      * @see parserClass::getChildClassList()\r
1347      * @uses $definitechild\r
1348      */\r
1349     function getDefiniteChildren($parclass, $file)\r
1350     {\r
1351         if (isset($this->definitechild[$parclass][$file])) \r
1352             return $this->definitechild[$parclass][$file];\r
1353         return false;\r
1354     }\r
1355 }\r
1356 ?>\r