home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 June / ENTER.ISO / files / xampp-win32-1.4.5-installer.exe / xampp / Classes.inc < prev    next >
Encoding:
Text File  |  2004-03-24  |  37.5 KB  |  942 lines

  1. <?php
  2. //
  3. // +------------------------------------------------------------------------+
  4. // | phpDocumentor                                                          |
  5. // +------------------------------------------------------------------------+
  6. // | Copyright (c) 2000-2003 Joshua Eichorn, Gregory Beaver                 |
  7. // | Email         jeichorn@phpdoc.org, cellog@phpdoc.org                   |
  8. // | Web           http://www.phpdoc.org                                    |
  9. // | Mirror        http://phpdocu.sourceforge.net/                          |
  10. // | PEAR          http://pear.php.net/package-info.php?pacid=137           |
  11. // +------------------------------------------------------------------------+
  12. // | This source file is subject to version 3.00 of the PHP License,        |
  13. // | that is available at http://www.php.net/license/3_0.txt.               |
  14. // | If you did not receive a copy of the PHP license and are unable to     |
  15. // | obtain it through the world-wide-web, please send a note to            |
  16. // | license@php.net so we can mail you a copy immediately.                 |
  17. // +------------------------------------------------------------------------+
  18. //
  19.  
  20. /**
  21.  * Intermediate class parsing structure.
  22.  * @package phpDocumentor
  23.  * @author Greg Beaver <cellog@users.sourceforge.net>
  24.  * @since 1.0rc1
  25.  * @version $Id: Classes.inc,v 1.52.2.3 2003/08/13 20:01:51 CelloG Exp $
  26.  */
  27. /**
  28.  * Intermediate class parsing structure.
  29.  *
  30.  * The {@link phpDocumentor_IntermediateParser} class uses this class and its
  31.  * cousin, {@link ProceduralPages} to organize all parsed source code elements.
  32.  * Data is fed to each immediately after it is parsed, and at conversion time,
  33.  * everything is organized.
  34.  *
  35.  * The Classes class is responsible for all inheritance, including resolving
  36.  * name conflicts between classes, determining which classes extend other
  37.  * classes, and is responsible for all inheritance of documentation.
  38.  * {@internal
  39.  * This structure parses classes, vars and methods by file, and then iterates
  40.  * over the class tree to set up inheritance.  The {@link Inherit()}
  41.  * method is the meat of the class, and processes the class trees from root to
  42.  * branch, ensuring that parsing order is unimportant.}}
  43.  * @package phpDocumentor
  44.  * @author Greg Beaver <cellog@users.sourceforge.net>
  45.  * @since 1.0rc1
  46.  * @version $Id: Classes.inc,v 1.52.2.3 2003/08/13 20:01:51 CelloG Exp $
  47.  */
  48. class Classes
  49. {
  50.     /**#@+
  51.      * @access private
  52.      */
  53.     /**
  54.      * file being parsed, used in every add function to match up elements with 
  55.      * the file that contains them
  56.      *
  57.      * This variable is used during parsing to associate class elements added
  58.      * to the data structures that contain them with the file they reside in
  59.      * @see addClass(), addMethod(), addVar(), nextFile()
  60.      * @var string
  61.      */
  62.     var $curfile;
  63.     /**
  64.      * class being parsed, used to match up methods and vars with their parent
  65.      * class
  66.      *
  67.      * This variable is used during parsing to associate class elements added
  68.      * to the data structures that contain them with the file they reside in
  69.      * @see addMethod(), addVar()
  70.      * @var string
  71.      */
  72.     var $curclass;
  73.     
  74.     /**
  75.      * Used when a definite match is made between a parent class and a child
  76.      * class
  77.      *
  78.      * This variable is used in post-parsing.
  79.      *
  80.      * Format: array(parent => array(parentfile => array(child => childfile)))
  81.      * @var array
  82.      */
  83.     var $definitechild;
  84.     /**
  85.      * array of parsed classes organized by the name of the file that contains
  86.      * the class.
  87.      *
  88.      * Format:
  89.      * array(filename => array(classname => {@link parserClass}))
  90.      * @var array
  91.      */
  92.     var $classesbyfile = array();
  93.     /**
  94.      * array of file names organized by classes that are in the file.
  95.      *
  96.      * This structure is designed to handle name conflicts.  Two files can
  97.      * contain classes with the same name, and this array will record both
  98.      * filenames to help control linking and inheritance errors
  99.      *
  100.      * Format:<pre>
  101.      * array(classname => array(name of file containing classname,
  102.      *                          name of file 2 containing classname...)</pre>
  103.      * @var array
  104.      */
  105.     var $classesbynamefile = array();
  106.     /**
  107.      * array of parsed methods organized by the file that contains them.
  108.      *
  109.      * Format:<pre>
  110.      * array(filename => array(classname => array({@link parserMethod} 1, 
  111.      *                                            {@link parserMethod} 2,...))</pre>
  112.      * @var array
  113.      */
  114.     var $methodsbyfile = array();
  115.     /**
  116.      * array of parsed vars organized by the file that contains them.
  117.      *
  118.      * Format:
  119.      * array(filename => array(classname => array({@link parserVar} 1, {@link parserVar} 2,...))
  120.      * @var array
  121.      */
  122.     var $varsbyfile = array();
  123.     /**
  124.      * keeps track of extend declarations by file, used to find inheritance
  125.      *
  126.      * Format:
  127.      * array(filename => array(classname => parentclassname))
  128.      * @var array
  129.      */
  130.     var $extendsbyfile = array();
  131.     /**
  132.      * Keeps track of child classes by file.
  133.      * Since phpDocumentor can document collections of files that contain name
  134.      * conflicts (PHP would give a fatal error), it
  135.      * is impossible to assume a class that declares "extends foo" necessarily
  136.      * extends the class foo in file X.  It could be an
  137.      * extended class of class foo in file Y.  Because of this, phpDocumentor
  138.      * relies on packaging to resolve the name conflict
  139.      * This array keeps track of the packages of a child class
  140.      *
  141.      * Format:
  142.      * array(parentclassname => array(filename => array(childclassname =>
  143.      *                                      array(packagename, packagename)))
  144.      * @var array
  145.      */
  146.     var $classchildrenbyfile = array();
  147.     /**
  148.      * Keeps track of class packages found in a file.
  149.      * This is used in {@link getParentClass()} to determine the number of
  150.      * packages in a file, in order to resolve inheritance issues
  151.      * Format: array(filename => array(packagename1, packagename2,...))
  152.      * @var array
  153.      */
  154.     var $classpackagebyfile = array();
  155.     /**
  156.      * a tree of class inheritance by name.
  157.      *
  158.      * format:<pre>
  159.      * array(childname => parentname,
  160.      *       childname1 => parentname1,
  161.      *       rootname => 0, ...
  162.      *      )</pre>
  163.      * @var array
  164.      * @see Converter::generateSortedClassTreeFromClass()
  165.      */
  166.     var $classparents = array();
  167.     /**
  168.      * Keeps track of package and subpackage for each class name, organized
  169.      * by package
  170.      *
  171.      * Format:<pre>
  172.      * array(classname => array(path => array(package,subpackage),
  173.      *                          path2 => array(package,subpackage),...))</pre>
  174.      * @var array
  175.      */
  176.     var $classpathpackages = array();
  177.     /**
  178.      * used to delete duplicates in the same package to avoid documentation errors
  179.      *
  180.      * Specifically used in {@link Converter::checkKillClass()}
  181.      */
  182.     var $killclass = array();
  183.     /**
  184.      * array of methods by package and class
  185.      *
  186.      * format:<pre>
  187.      * array(packagename =>
  188.      *         array(classname =>
  189.      *               array(methodname1 => {@link parserMethod} class,
  190.      *                     methodname2 => {@link parserMethod} class,...)
  191.      *                      )
  192.      *              )
  193.      *      )</pre>
  194.      * @var array
  195.      * @see Converter
  196.      */
  197.     var $methods = array();
  198.     
  199.     /**
  200.      * array of class variables by package and class
  201.      *
  202.      * format:<pre>
  203.      * array(packagename =>
  204.      *         array(classname =>
  205.      *                array(variablename1 => {@link parserMethod} class,
  206.      *                      variablename2 => {@link parserMethod} class,...
  207.      *                     )
  208.      *              )
  209.      *      )</pre>
  210.      * @var array
  211.      * @see Converter
  212.      */
  213.     var $vars = array();
  214.     /**
  215.      * Reverse class_packages_by_file, used to prevent duplicates
  216.      * @var array Format: array(packagename => 1)
  217.      */
  218.     var $revcpbf = array();
  219.     /**
  220.      * All classes with no parents (no extends clause) are tracked in this array
  221.      * by the file that contains them.
  222.      *
  223.      * Format:<pre>
  224.      * array(classname => array(name of file1 that contains root classname,
  225.      *                          name of file2 that contains root classname,...))</pre>
  226.      * @var array
  227.      */
  228.     var $roots = array();
  229.     
  230.     /**
  231.      * array of all files that contain classes with the same name
  232.      * @var array Format: (classname => array(path1, path2,...))
  233.      */
  234.     var $potentialclassconflicts = array();
  235.     
  236.     /**
  237.      * array of all inter-package name conflicts of classes
  238.      *
  239.      * This array allows documentation of PHP namespace conflicts that would
  240.      * occur should a user try to include these files in the same file
  241.      * @var array Format: (classname => array(path1, path2,...))
  242.      */
  243.     var $classconflicts = array();
  244.     /**#@-*/
  245.     /**
  246.      * While parsing, add a class to the list of parsed classes
  247.      *
  248.      * sets up the {@link $classesbyfile, $classesbynamefile, $extendsbyfile},
  249.      * {@link $classchildrenbyfile, $roots} arrays, and sets {@link $curclass}
  250.      * @param parserClass &$element element is a {@link parserClass}
  251.      * @uses addPackageToFile() marks the current class's package as being
  252.      *                          present in a file
  253.      */
  254.     function addClass(&$element)
  255.     {
  256.         $this->curclass = $element->getName();
  257.         $element->curfile = $this->curfile;
  258.         if (isset($this->classesbyfile[$this->curfile][$this->curclass]))
  259.         {
  260.             addWarning(PDERROR_ELEMENT_IGNORED,'class',$this->curclass,$this->curfile);
  261.             $this->curclass = false;
  262.             return;
  263.         }
  264.         $this->classesbyfile[$this->curfile][$this->curclass] = $element;
  265.         $this->classesbynamefile[$this->curclass][] = $this->curfile;
  266.         $this->extendsbyfile[$this->curfile][$this->curclass] = $element->getExtends();
  267.         $this->classchildrenbyfile[$element->getExtends()][$this->curfile][$this->curclass][] = $element->docblock->package;
  268.         if ($element->docblock->getExplicitPackage())
  269.         $this->addPackageToFile($element->docblock->package);
  270.         if (!$element->getExtends())
  271.         {
  272.             $this->roots[$this->curclass][] = $this->curfile;
  273.         }
  274.     }
  275.     
  276.     /**
  277.      * While parsing, add a method to the list of parsed methods
  278.      *
  279.      * sets up the {@link $methodsbyfile} array using {@link $curfile} and
  280.      * {@link $curclass}
  281.      * @param parserMethod &$element element is a {@link parserMethod}
  282.      */
  283.     function addMethod(&$element)
  284.     {
  285.         if (!$this->curclass) return;
  286.         $this->methodsbyfile[$this->curfile][$this->curclass][] = $element;
  287.     }
  288.     
  289.     /**
  290.      * While parsing, add a variable to the list of parsed variables
  291.      *
  292.      * sets up the {@link $varsbyfile} array using {@link $curfile} and {@link $curclass}
  293.      * @param parserVar &$element element is a {@link parserVar}
  294.      */
  295.     function addVar(&$element)
  296.     {
  297.         if (!$this->curclass) return;
  298.         $this->varsbyfile[$this->curfile][$this->curclass][] = $element;
  299.     }
  300.     
  301.     /**
  302.      * Prepare to parse a new file
  303.      *
  304.      * sets {@link $curfile} to $file and {@link $curclass} to false (no class being parsed)
  305.      * @param string $file file currently being parsed
  306.      */
  307.     function nextFile($file)
  308.     {
  309.         $this->curfile = $file;
  310.         $this->curclass = false;
  311.     }
  312.     
  313.     /**
  314.      * Mark a package as being used in a class
  315.      *
  316.      * {@source}
  317.      * @param string $package package name
  318.      */
  319.     function addPackageToFile($package)
  320.     {
  321.         if (!isset($this->revcpbf[$this->curfile][$package]))
  322.         $this->classpackagebyfile[$this->curfile][] = $package;
  323.         $this->revcpbf[$this->curfile][$package] = 1;
  324.     }
  325.     
  326.     /**
  327.      * Find the parent class of $class, and set up structures to note this fact
  328.      *
  329.      * Modifies the {@link parserClass} element in {@link $classesbyfile} to use
  330.      * the parent's package, and inherit methods/vars
  331.      * @param string $class child class to find parent class
  332.      * @param string $file file child class is located in
  333.      * @uses $definitechild if a match is made between a parent class and parameter
  334.      *                      $class in file $file, then definitechild is set here
  335.      * @uses getParentClass() to find the parent class
  336.      */
  337.     function setClassParent($class,$file)
  338.     {
  339.         if (is_array($par = $this->getParentClass($class,$file)))
  340.         {
  341. //            phpDocumentor_out("$file class $class extends ".$par[1]." file ".$par[0]."\n");
  342.             $this->classesbyfile[$file][$class]->setParent($par[1],$par[0],$this);
  343.             $this->definitechild[$par[1]][$par[0]][$class] = $file;
  344.         } else
  345.         {
  346.             $this->classesbyfile[$file][$class]->setParentNoClass($par);
  347.         }
  348.     }
  349.     
  350.     /**
  351.      * Main processing engine for setting up class inheritance.
  352.      *
  353.      * This function uses {@link $roots} to traverse the inheritance tree via
  354.      * {@link processChild()} and returns the data structures
  355.      * phpDocumentor_IntermediateParser needs to convert parsed data
  356.      * to output using {@link phpDocumentor_IntermediateParser::Convert()}
  357.      * @param phpDocumentor_IntermediateParser
  358.      * @uses processChild() set up inheritance
  359.      */
  360.     function Inherit(&$render)
  361.     {
  362.         phpDocumentor_out("\nProcessing Class Inheritance\n\n");
  363.         flush();
  364.         phpDocumentor_out("\nProcessing Root Trees\n\n");
  365.         flush();
  366.         foreach($this->roots as $class => $files)
  367.         {
  368.             for ($i=0; $i<count($files); $i++)
  369.             {
  370.                 $this->processChild($render,$class,$files[$i]);
  371.             }
  372.         }
  373.         if (0)
  374.         foreach($this->classesbyfile as $i => $j)
  375.         {
  376.             foreach($j as $k => $m)
  377.             {
  378.                 var_dump($i,$k);
  379.                 if ($i == 'iConverter')
  380.                 {
  381.                     var_dump($j);
  382.                 }
  383.             }
  384.         }
  385.         phpDocumentor_out("\nProcessing leftover classes (classes that extend root classes not found in the same package)\n");
  386.         flush();
  387.         foreach($this->classesbyfile as $i => $j)
  388.         {
  389.             foreach($j as $k => $m)
  390.             {
  391.                 $this->processChild($render,$k,$i,true);
  392.             }
  393.         }
  394.         phpDocumentor_out("done processing leftover classes\n");
  395.         flush();
  396.         $this->setupClassConflicts();
  397.     }
  398.     
  399.     /**
  400.      * Transfers actual conflicts from {@link $potentialClassconflicts} to
  401.      * {@link $classconflicts}
  402.      * @access private
  403.      * @uses $potentialclassconflicts transfers values to {@link $classconflicts}
  404.      */
  405.     function setupClassConflicts()
  406.     {
  407.         foreach($this->potentialclassconflicts as $class => $paths)
  408.         {
  409.             if (count($paths) - 1)
  410.             { //conflict
  411.                 $package = array();
  412.                 foreach($paths as $path)
  413.                 {
  414.                     // create a list of conflicting classes in each package
  415.                     if (isset($this->classpathpackages[$class][$path]))
  416.                     $package[$this->classpathpackages[$class][$path][0]][] = $path;
  417.                 }
  418.                 foreach($package as $pathpackages)
  419.                 {
  420.                     // if at least 2 functions exist in the same package, delete all but the first one and add warnings
  421.                     if (count($pathpackages) - 1)
  422.                     {
  423.                         for($i=1; $i < count($pathpackages); $i++)
  424.                         {
  425.                             if (isset($this->classesbyfile[$pathpackages[$i]]))
  426.                             {
  427.                                 addWarning(PDERROR_ELEMENT_IGNORED,'class',$class,$pathpackages[$i]);
  428.                                 $this->killClass($class,$pathpackages[$i]);
  429.                                 $oth = array_flip($paths);
  430.                                 unset($paths[$oth[$pathpackages[$i]]]);
  431.                             }
  432.                         }
  433.                     }
  434.                 }
  435.                 $this->classconflicts[$class] = $paths;
  436.             }
  437.         }
  438.     }
  439.     
  440.     /**
  441.      * If a package contains two classes with the same name, this function finds
  442.      * that conflict
  443.      *
  444.      * Returns the {@link $classconflicts} entry for class $class, minus its own path
  445.      * @return mixed returns false if no conflicts, or an array of paths containing conflicts
  446.      */
  447.     function getConflicts($class)
  448.     {
  449.         if (!isset($this->classconflicts[$class])) return false;
  450.         $a = array();
  451.         foreach($this->classconflicts[$class] as $conflict)
  452.         {
  453.             $a[$this->classesbyfile[$conflict][$class]->docblock->package] = $this->classesbyfile[$conflict][$class];
  454.         }
  455.         return $a;
  456.     }
  457.     
  458.     /**
  459.      * sets up {@link $killclass} for use by Converter::checkKillClass()
  460.      * @access private
  461.      */
  462.     function killClass($class,$path)
  463.     {
  464.         $this->killclass[$class][$path] = true;
  465.     }
  466.     
  467.     /**
  468.      * This function recursively climbs up the class tree, setting inherited
  469.      * information like package and adds the elements to phpDocumentor_IntermediateParser.
  470.      *
  471.      * Using structures defined in {@link Classes}, the function first sets package information,
  472.      * and then seeks out child classes.
  473.      * It uses 3 tests to determine whether a class is a child class.
  474.      * <ol>
  475.      *    <li>child class is in the same file as the parent class and extends parent class</li>
  476.      *    <li>child class is in a different file and specifies the parent's @package in its docblock</li>
  477.      *    <li>child class is in a different file and is in a different @package, with one possible parent class</li>
  478.      * </ol>
  479.      * @param phpDocumentor_IntermediateParser &$render
  480.      * @param string $class class to process
  481.      * @param string $file name of file $class is located in
  482.      * @param boolean $furb flag used privately to control informational output while parsing
  483.      *                            (used when processing leftover classes in {@link Inherit()}
  484.      * @global    string    default package, usually "default"
  485.      */
  486.     function processChild(&$render,$class,$file,$furb = false)
  487.     {
  488.         global $phpDocumentor_DefaultPackageName;
  489.         if (isset($this->classesbyfile[$file][$class]->processed)) return;
  490.         $this->potentialclassconflicts[$class][] = $file;
  491.         if ($furb) phpDocumentor_out("Processing $class in file $file\n");
  492.         flush();
  493.         $this->classesbyfile[$file][$class]->processed = true;
  494.         $db = $this->classesbyfile[$file][$class];
  495.         $render->addUses($db,$file);
  496.         if (!$render->parsePrivate)
  497.         {
  498.             // if this class has an @access private, and parse private is disabled, remove it
  499.             if ($db->docblock->hasaccess)
  500.             {
  501.                 $aaa = $db->docblock->getKeyword('access');
  502.                 if ($aaa->getString() == 'private')
  503.                 {
  504.                     if (isset($this->varsbyfile[$file]) && isset($this->varsbyfile[$file][$class])) unset($this->varsbyfile[$file][$class]);
  505.                     unset($this->methodsbyfile[$file][$class]);
  506.                     $this->classesbyfile[$file][$class]->ignore = true;
  507.                     // if this is a root class, remove it from the roots array
  508.                     if (isset($this->roots[$class]))
  509.                     foreach($this->roots[$class] as $i => $files)
  510.                     {
  511.                         // find the file kkey and unset
  512.                         if ($files == $file) unset($this->roots[$class][$i]);
  513.                     }
  514.                     // if this is a child, remove it from the list of child classes of its parent
  515.                     if ($db->getExtends()) unset($this->classchildrenbyfile[$db->getExtends()][$file]);
  516.                     return;
  517.                 }
  518.             }
  519.         }
  520.         if ($render->packageoutput)
  521.         {
  522.             if (!in_array($db->docblock->package,$render->packageoutput))
  523.             {
  524.                 if (isset($this->varsbyfile[$file][$class]))
  525.                 unset($this->varsbyfile[$file][$class]);
  526.                 if (isset($this->methodsbyfile[$file][$class]))
  527.                 unset($this->methodsbyfile[$file][$class]);
  528.                 $this->classesbyfile[$file][$class]->ignore = true;
  529.                 if (isset($this->roots[$class]))
  530.                 foreach($this->roots[$class] as $i => $files)
  531.                 {
  532.                     if ($files == $file) unset($this->roots[$class][$i]);
  533.                 }
  534.                 if ($db->getExtends()) unset($this->classchildrenbyfile[$db->getExtends()][$file]);
  535.                 return;
  536.             }
  537.         }
  538.         $this->setClassParent($class,$file);
  539.         $db = $this->classesbyfile[$file][$class];
  540.         if ($furb && !is_array($db->parent))
  541.         {
  542. //            debug("furb adding $class $file to roots");
  543.             $this->roots[$class][] = $file;
  544.         }
  545.         // fix for 591396
  546.         if (!$db->docblock->getExplicitPackage())
  547.         {
  548.             $a = $render->proceduralpages->pagepackages[$file];
  549.             if ($a[0] != $phpDocumentor_DefaultPackageName)
  550.             {
  551.                 // inherit page package
  552.                 $this->classesbyfile[$file][$class]->docblock->package = $a[0];
  553.             }
  554.         }
  555.         if ($this->classesbyfile[$file][$class]->docblock->package == $render->proceduralpages->pagepackages[$file][0])
  556.         {
  557.             if ($this->classesbyfile[$file][$class]->docblock->subpackage == '')
  558.                 $this->classesbyfile[$file][$class]->docblock->subpackage = $render->proceduralpages->pagepackages[$file][1];
  559.         }
  560.         $db = $this->classesbyfile[$file][$class];
  561.         $render->addPackageParent($db);
  562.         $render->addPageIfNecessary($file, $db);
  563.         if ($access = $db->docblock->getKeyword('access'))
  564.         {
  565.             if (!is_string($access)) $access = $access->getString();
  566.             if (($access == 'private') && (!$render->parsePrivate))
  567.             {
  568.                 if (isset($this->varsbyfile[$file]) && isset($this->varsbyfile[$file][$class]))
  569.                 foreach($this->varsbyfile[$file][$class] as $i => $vr)
  570.                 {
  571.                     $vr->docblock->addKeyword('access','private');
  572.                     $this->varsbyfile[$file][$class][$i] = $vr;
  573.                 }
  574.                 if (isset($this->methodsbyfile[$file]) && isset($this->methodsbyfile[$file][$class]))
  575.                 foreach($this->methodsbyfile[$file][$class] as $i => $vr)
  576.                 {
  577.                     $vr->docblock->addKeyword('access','private');
  578.                     $this->methodsbyfile[$file][$class][$i] = $vr;
  579.                 }
  580.             }
  581.         }
  582.         $this->classpathpackages[$class][$file] = array($db->docblock->package,$db->docblock->subpackage);
  583.         if ($db->docblock->getExplicitPackage())
  584.         $render->proceduralpages->addClassPackageToFile($file,$db->docblock->package,$db->docblock->subpackage);
  585.         $render->addElementToPage($db,$file);
  586.         if (isset($this->varsbyfile[$file]) && isset($this->varsbyfile[$file][$class]))
  587.         foreach($this->varsbyfile[$file][$class] as $i => $vr)
  588.         {
  589.             $vr->docblock->package = $db->docblock->package;
  590.             $vr->docblock->subpackage = $db->docblock->subpackage;
  591.             $render->addElementToPage($vr,$file);
  592.             $render->addUses($vr,$file);
  593.             $this->varsbyfile[$file][$class][$i] = $vr;
  594.             $this->vars[$db->docblock->package][$class][$vr->getName()] = $vr;
  595.         }
  596.         if (isset($this->methodsbyfile[$file]) && isset($this->methodsbyfile[$file][$class]))
  597.         foreach($this->methodsbyfile[$file][$class] as $i => $vr)
  598.         {
  599.             $vr->docblock->package = $db->docblock->package;
  600.             $vr->docblock->subpackage = $db->docblock->subpackage;
  601.             $render->addElementToPage($vr,$file);
  602.             $render->addUses($vr,$file);
  603.             $this->methodsbyfile[$file][$class][$i] = $vr;
  604.             $this->methods[$db->docblock->package][$class][$vr->getName()] = $vr;
  605.         }
  606.         $this->classpackages[$class][] = array($db->docblock->package,$db->docblock->subpackage);
  607.         if (is_array($db->parent))
  608.         $this->classparents[$db->docblock->package][$class] = $db->parent[1];
  609.         else
  610.         $this->classparents[$db->docblock->package][$class] = $db->getExtends();
  611.         if (is_array($db->parent))
  612.         {
  613.             $z = $this->getClass($db->parent[1],$db->parent[0]);
  614.             $this->classchildren[$z->docblock->package][$db->parent[1]][] = $db;
  615.         }
  616.         if (isset($this->classchildrenbyfile[$class]))
  617.         {
  618.             foreach($this->classchildrenbyfile[$class] as $childfile => $other)
  619.             {
  620.                 // test 1, inherits in same file (must be same package)
  621.                 if ($childfile == $file)
  622.                 {
  623.                     foreach($other as $child => $packages)
  624.                     {
  625. //                        debug("parent $class same file $child");
  626.                         $this->processChild($render,$child,$childfile);
  627.                         $x = $this->getClass($child,$childfile);
  628.                         if ($x->docblock->package != $GLOBALS['phpDocumentor_DefaultPackageName'])
  629.                         {
  630.                             // child package need root for class trees
  631.                             if ($x->docblock->package != $db->docblock->package)
  632.                             {
  633. //                            debug("adding $child in $childfile 1");
  634.                                 $this->roots[$child][] = $childfile;
  635.                             }
  636.                         }
  637.                     }
  638.                 } else
  639.                 {
  640.                 // test 2, different file, same package
  641.                     foreach($other as $child => $packages)
  642.                     {
  643.                         for($j=0; $j<count($packages); $j++)
  644.                         {
  645.                             if ($this->classesbyfile[$file][$class]->docblock->package == $packages[$j])
  646.                             {
  647.                                 $this->processChild($render,$child,$childfile);
  648. //                                debug("$childfile diff file $child, parent $class, same package ".$packages[$j]);
  649.                             } else
  650.                             {
  651.                                 // test 3, different file, different package, only 1 parent is possible
  652.                                 if (isset($this->classesbynamefile[$child]))
  653.                                 {
  654.                                     // 1 possible parent
  655.                                     if (count($this->classesbynamefile[$class]) == 1)
  656.                                     {
  657. //                                        debug("$childfile diff file $child, diff package, 1 possible parent root $class");
  658.                                         $this->processChild($render,$child,$childfile);
  659.                                         $x = $this->getClass($child,$childfile);
  660.                                         if ($x->docblock->package != $GLOBALS['phpDocumentor_DefaultPackageName'])
  661.                                         {
  662.                                             // child package need root for class trees
  663.                                             if ($x->docblock->package != $db->docblock->package)
  664.                                             {
  665. //                                                debug("adding roots $child in $childfile 2");
  666.                                                 $this->roots[$child][] = $childfile;
  667.                                             }
  668.                                         }
  669.                                     }
  670.                                 }
  671.                             }
  672.                         }
  673.                     }
  674.                 }
  675.             }
  676.         }
  677.     }
  678.     
  679.     /**
  680.      * Get the parserClass representation of a class from its name and file
  681.      * @return parserClass
  682.      * @param string $class classname
  683.      * @param string $file file classname is located in
  684.      */
  685.     function &getClass($class, $file)
  686.     {
  687. //        debug("getClass called with class $class file $file");
  688.         return $this->classesbyfile[$file][$class];
  689.     }
  690.     
  691.     /**
  692.      * Used by {@link parserData::getClasses()} to retrieve classes defined in file $path
  693.      *
  694.      * retrieves the array entry from {@link $classesbyfile} for $path
  695.      * @param string $path full path to filename
  696.      * @return mixed returns false if no classes defined in the file, otherwise returns an array of {@link parserClass}es
  697.      */
  698.     function getClassesInPath($path)
  699.     {
  700.         if (!isset($this->classesbyfile[$path])) return false;
  701.         return $this->classesbyfile[$path];
  702.     }
  703.     
  704.     /**
  705.      * called by {@link parserClass::hasMethods()}.  Should not be directly called
  706.      * @access private
  707.      * @param string $file
  708.      * @param string $class
  709.      */
  710.     function &hasMethods($file,$class)
  711.     {
  712.         return isset($this->methodsbyfile[$file][$class]);
  713.     }
  714.     
  715.     /**
  716.      * called by {@link parserClass::hasMethod()}.  Should not be directly called
  717.      * @param string $file
  718.      * @param string $class
  719.      * @param string $name method name
  720.      * @access private
  721.      */
  722.     function hasMethod($class, $file, $name)
  723.     {
  724.         if (!$this->hasMethods($file, $class)) return false;
  725.         for($i=0; $i<count($this->methodsbyfile[$file][$class]); $i++)
  726.         {
  727.             if ($this->methodsbyfile[$file][$class][$i]->getName() == $name) return true;
  728.         }
  729.         return false;
  730.     }
  731.     
  732.     /**
  733.      * called by {@link parserClass::hasVar()}.  Should not be directly called
  734.      * @param string $file
  735.      * @param string $class
  736.      * @param string $name var name
  737.      * @access private
  738.      */
  739.     function hasVar($class, $file, $name)
  740.     {
  741.         if (!$this->hasVars($file, $class)) return false;
  742.         for($i=0; $i<count($this->varsbyfile[$file][$class]); $i++)
  743.         {
  744.             if ($this->varsbyfile[$file][$class][$i]->getName() == $name) return true;
  745.         }
  746.         return false;
  747.     }
  748.     
  749.     /**
  750.      * called by {@link parserClass::hasVars()}.  Should not be directly called
  751.      * @access private
  752.      * @param string $file
  753.      * @param string $class
  754.      */
  755.     function &hasVars($file, $class)
  756.     {
  757.         return isset($this->varsbyfile[$file][$class]);
  758.     }
  759.     
  760.     /**
  761.      * called by {@link parserClass::getMethods()}.  Should not be directly called
  762.      * @access private
  763.      * @param string $class
  764.      * @param string $file
  765.      */
  766.     function &getMethods($class, $file)
  767.     {
  768.         if (!isset($this->methodsbyfile[$file][$class])) return false;
  769.         return $this->methodsbyfile[$file][$class];
  770.     }
  771.     
  772.     /**
  773.      * called by {@link parserClass::getVars()}.  Should not be directly called
  774.      * @access private
  775.      * @param string $class
  776.      * @param string $file
  777.      */
  778.     function &getVars($class, $file)
  779.     {
  780.         if (!isset($this->varsbyfile[$file][$class])) return false;
  781.         return $this->varsbyfile[$file][$class];
  782.     }
  783.     
  784.     /**
  785.      * called by {@link parserClass::getMethod()}.  Should not be directly called
  786.      * @param string $class
  787.      * @param string $file
  788.      * @param string $name method name
  789.      * @access private
  790.      */
  791.     function getMethod($class, $file, $name)
  792.     {
  793.         if (!$this->hasMethod($class, $file, $name)) return false;
  794.         for($i=0; $i<count($this->methodsbyfile[$file][$class]); $i++)
  795.         {
  796.             if ($this->methodsbyfile[$file][$class][$i]->getName() == $name) return $this->methodsbyfile[$file][$class][$i];
  797.         }
  798.     }
  799.     
  800.     /**
  801.      * called by {@link parserClass::getVar()}.  Should not be directly called
  802.      * @param string $class
  803.      * @param string $file
  804.      * @param string $name var name
  805.      * @access private
  806.      */
  807.     function getVar($class, $file, $name)
  808.     {
  809.         if (!$this->hasVar($class, $file, $name)) return false;
  810.         for($i=0; $i<count($this->varsbyfile[$file][$class]); $i++)
  811.         {
  812.             if ($this->varsbyfile[$file][$class][$i]->getName() == $name) return $this->varsbyfile[$file][$class][$i];
  813.         }
  814.     }
  815.     
  816.     /**
  817.      * Search for a class in a package
  818.      * @return mixed returns false if no class in $package, otherwise returns a {@link parserClass}
  819.      * @param string $class classname
  820.      * @param string $package package classname is in
  821.      */
  822.     function &getClassByPackage($class,$package)
  823.     {
  824.         if (!isset($this->classesbynamefile[$class]))
  825.         {
  826. //            addWarning(PDERROR_CLASS_NOT_IN_PACKAGE,$class,$package); // removed, too many warnings, not very useful
  827.             return false;
  828.         }
  829.         for($i=0; $i < count($this->classesbynamefile[$class]); $i++)
  830.         {
  831.                         $cls = $this->classesbyfile[$this->classesbynamefile[$class][$i]][$class];
  832.                         $pkg = $cls->getPackage();
  833.             if ($pkg == $package)
  834.                                 return $cls;
  835.         }
  836. //        addWarning(PDERROR_CLASS_NOT_IN_PACKAGE,$class,$package);
  837.         return false;
  838.     }
  839.     
  840.     /**
  841.      * Find the parent class of a class in file $file
  842.      * uses 3 tests to find the parent classname:
  843.      * <ol>
  844.      *    <li>only one class with the parent classname</li>
  845.      *    <li>more than one class, but only one in the same file as the child</li>
  846.      *    <li>only one parent class in the same package as the child</li>
  847.      * </ol>
  848.      * @return mixed false if no parent class, a string if no parent class found by that name,
  849.      *                and an array(file parentclass is in,parentclassname)
  850.      */
  851.     function getParentClass($class,$file)
  852.     {
  853.         if (!isset($this->classesbyfile[$file][$class]))
  854.         {
  855.             return false;
  856.         }
  857.         $element = $this->classesbyfile[$file][$class];
  858.         if (!($ex = $element->getExtends())) return false;
  859.         // first check to see if there is one and only one class with the parent class's name
  860.         if (isset($this->classesbynamefile[$ex]))
  861.         {
  862.             if (count($this->classesbynamefile[$ex]) == 1)
  863.             {
  864.                 if ($this->classesbyfile[$this->classesbynamefile[$ex][0]][$ex]->ignore) return $ex;
  865.                 return array($this->classesbynamefile[$ex][0],$ex);
  866.             } else
  867.             {
  868.                 // next check to see if there is a parent class in the same file
  869.                 if (isset($this->classesbyfile[$file][$ex]))
  870.                 {
  871.                     if ($this->classesbyfile[$file][$ex]->ignore) return $ex;
  872.                     return array($file,$ex);
  873.                 }
  874.                 // next check to see if there is only one package used in the file, try to resolve it that way
  875.                 if (isset($this->classpackagebyfile[$file]))
  876.                 {
  877.                     if (count($this->classpackagebyfile[$file]) == 1)
  878.                     {
  879.                         for($i=0;$i<count($this->classesbynamefile[$ex]);$i++)
  880.                         {
  881.                             if ($this->classesbyfile[$this->classesbynamefile[$ex][$i]][$ex]->getPackage() == $this->classpackagebyfile[$file][0])
  882.                             {
  883.                                 if ($this->classesbyfile[$this->classesbynamefile[$ex][$i]][$ex]->ignore) return $ex;
  884.                                 return array($this->classesbynamefile[$ex][$i],$ex);
  885.                             }
  886.                         }
  887.                     }
  888.                 }
  889.                 // name conflict
  890.                 addWarning(PDERROR_INHERITANCE_CONFLICT, $class, $file, $ex);
  891.                 return $ex;
  892.             }
  893.         } else
  894.         {
  895.             addWarning(PDERROR_PARENT_NOT_FOUND, $class, $ex);
  896.             return $ex;
  897.         }
  898.     }
  899.     
  900.     /**
  901.      * Get a list of all root classes indexed by package.  Used to generate
  902.      * class trees by {@link Converter}
  903.      * @return array array(package => array(rootclassname, rootclassname,...),...)
  904.      */
  905.     function getRoots()
  906.     {
  907.         $roots = array();
  908.         foreach($this->roots as $class => $files)
  909.         {
  910.             if (count($files))
  911.             {
  912.                 foreach($files as $i => $boofou)
  913.                 {
  914.                     $x = $this->getClass($class,$files[$i]);
  915.                     $roots[$x->getPackage()][] = $class;
  916.                 }
  917.             }
  918.         }
  919.         foreach($roots as $package => $root)
  920.         {
  921.             usort($roots[$package],"strnatcasecmp");
  922.         }
  923.         return $roots;
  924.     }
  925.     
  926.     /**
  927.      * Get all classes confirmed in parsing to be descended class $parclass in file $file
  928.      * @return mixed either false if no children, or array of format
  929.      *         array(childname => childfile,childname2 => childfile2,...)
  930.      * @param string $parclass name of parent class
  931.      * @param string $file file parent class is found in
  932.      * @see parserClass::getChildClassList()
  933.      * @uses $definitechild
  934.      */
  935.     function getDefiniteChildren($parclass,$file)
  936.     {
  937.         if (isset($this->definitechild[$parclass][$file])) return $this->definitechild[$parclass][$file];
  938.         return false;
  939.     }
  940. }
  941. ?>
  942.