| Viewing file:  Classes.inc (49.47 KB)      -rw-r--r-- Select action/file-type:
 
  (+) |  (+) |  (+) | Code (+) | Session (+) |  (+) | SDB (+) |  (+) |  (+) |  (+) |  (+) |  (+) | 
 
<?php
/**
 * Intermediate class parsing structure.
 *
 * phpDocumentor :: automatic documentation generator
 *
 * PHP versions 4 and 5
 *
 * Copyright (c) 2001-2007 Gregory Beaver
 *
 * LICENSE:
 *
 * This library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General
 * Public License as published by the Free Software Foundation;
 * either version 2.1 of the License, or (at your option) any
 * later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 * @category  ToolsAndUtilities
 * @package   phpDocumentor
 * @author    Greg Beaver <cellog@php.net>
 * @copyright 2001-2007 Gregory Beaver
 * @license   http://www.opensource.org/licenses/lgpl-license.php LGPL
 * @version   CVS: $Id: Classes.inc 243933 2007-10-10 01:18:25Z ashnazg $
 * @filesource
 * @link      http://www.phpdoc.org
 * @link      http://pear.php.net/PhpDocumentor
 * @see       parserDocBlock, parserInclude, parserPage, parserClass
 * @see       parserDefine, parserFunction, parserMethod, parserVar
 * @since     1.0rc1
 * @todo      CS cleanup - change package to PhpDocumentor
 */
 /**
 * Intermediate class parsing structure.
 *
 * The {@link phpDocumentor_IntermediateParser} class uses this class and its
 * cousin, {@link ProceduralPages} to organize all parsed source code elements.
 * Data is fed to each immediately after it is parsed, and at conversion time,
 * everything is organized.
 *
 * The Classes class is responsible for all inheritance, including resolving
 * name conflicts between classes, determining which classes extend other
 * classes, and is responsible for all inheritance of documentation.
 * {@internal
 * This structure parses classes, vars and methods by file, and then iterates
 * over the class tree to set up inheritance.  The {@link Inherit()}
 * method is the meat of the class, and processes the class trees from root to
 * branch, ensuring that parsing order is unimportant.}}
 *
 * @category  ToolsAndUtilities
 * @package   phpDocumentor
 * @author    Greg Beaver <cellog@php.net>
 * @copyright 2001-2007 Gregory Beaver
 * @license   http://www.opensource.org/licenses/lgpl-license.php LGPL
 * @version   Release: 1.4.3
 * @link      http://www.phpdoc.org
 * @link      http://pear.php.net/PhpDocumentor
 * @since     1.0rc1
 * @todo      CS cleanup - change package to PhpDocumentor
 */
 class Classes
 {
 /**#@+
 * @access private
 */
 /**
 * file being parsed, used in every add function to match up elements with
 * the file that contains them
 *
 * This variable is used during parsing to associate class elements added
 * to the data structures that contain them with the file they reside in
 * @see addClass(), addMethod(), addVar(), nextFile()
 * @var string
 */
 var $curfile;
 /**
 * class being parsed, used to match up methods and vars with their parent
 * class
 *
 * This variable is used during parsing to associate class elements added
 * to the data structures that contain them with the file they reside in
 * @see addMethod(), addVar()
 * @var string
 */
 var $curclass;
 
 /**
 * Used when a definite match is made between a parent class and a child
 * class
 *
 * This variable is used in post-parsing.
 *
 * Format:<pre>
 * array(
 *     parent => array(
 *         parentfile => array(
 *             child => childfile
 *         )
 *     )
 * )</pre>
 * @var array
 */
 var $definitechild;
 /**
 * array of parsed classes organized by the name of the file that contains
 * the class.
 *
 * Format:<pre>
 * array(
 *     filename => array(
 *         classname => {@link parserClass}
 *     )
 * )</pre>
 * @var array
 */
 var $classesbyfile = array();
 /**
 * array of file names organized by classes that are in the file.
 *
 * This structure is designed to handle name conflicts.  Two files can
 * contain classes with the same name, and this array will record both
 * filenames to help control linking and inheritance errors
 *
 * Format:<pre>
 * array(
 *     classname => array(
 *         name of file containing classname,
 *         name of file 2 containing classname,
 *         ...
 *     )
 * )</pre>
 * @var array
 */
 var $classesbynamefile = array();
 /**
 * array of parsed methods organized by the file that contains them.
 *
 * Format:<pre>
 * array(
 *     filename => array(
 *         classname => array(
 *             {@link parserMethod} 1,
 *             {@link parserMethod} 2,
 *             ...
 *         )
 *     )
 * )</pre>
 * @var array
 */
 var $methodsbyfile = array();
 /**
 * array of parsed vars organized by the file that contains them.
 *
 * Format:<pre>
 * array(
 *     filename => array(
 *         classname => array(
 *             {@link parserVar} 1,
 *             {@link parserVar} 2,
 *             ...
 *         )
 *     )
 * )</pre>
 * @var array
 */
 var $varsbyfile = array();
 /**
 * array of parsed class constants organized by the file that contains them.
 *
 * Format:<pre>
 * array(
 *     filename => array(
 *         classname => array(
 *             {@link parserConst} 1,
 *             {@link parserConst} 2,
 *             ...
 *         )
 *     )
 * )</pre>
 * @var array
 */
 var $constsbyfile = array();
 /**
 * keeps track of extend declarations by file, used to find inheritance
 *
 * Format:<pre>
 * array(
 *     filename => array(
 *         classname => parentclassname
 *     )
 * )</pre>
 * @var array
 */
 var $extendsbyfile = array();
 /**
 * Keeps track of child classes by file.
 * Since phpDocumentor can document collections of files that contain name
 * conflicts (PHP would give a fatal error), it
 * is impossible to assume a class that declares "extends foo" necessarily
 * extends the class foo in file X.  It could be an
 * extended class of class foo in file Y.  Because of this, phpDocumentor
 * relies on packaging to resolve the name conflict
 * This array keeps track of the packages of a child class
 *
 * Format:<pre>
 * array(
 *     parentclassname => array(
 *         filename => array(
 *             childclassname => array(
 *                 packagename,
 *                 packagename
 *             )
 *         )
 *     )
 * )</pre>
 * @var array
 */
 var $classchildrenbyfile = array();
 /**
 * Keeps track of class packages found in a file.
 * This is used in {@link getParentClass()} to determine the number of
 * packages in a file, in order to resolve inheritance issues
 * Format:<pre>
 * array(
 *     filename => array(
 *         packagename1,
 *         packagename2,
 *         ...
 *     )
 * )</pre>
 * @var array
 */
 var $classpackagebyfile = array();
 /**
 * a tree of class inheritance by name.
 *
 * Format:<pre>
 * array(
 *     childname => parentname,
 *     childname1 => parentname1,
 *     rootname => 0,
 *     ...
 * )</pre>
 * @var array
 * @see Converter::generateSortedClassTreeFromClass()
 */
 var $classparents = array();
 /**
 * Keeps track of package and subpackage for each class name, organized
 * by package
 *
 * Format:<pre>
 * array(
 *     classname => array(
 *         path => array(
 *             package,
 *             subpackage
 *         ),
 *         path2 => array(
 *             package,
 *             subpackage
 *         ),
 *         ...
 *     )
 * )</pre>
 * @var array
 */
 var $classpathpackages = array();
 /**
 * used to delete duplicates in the same package to avoid documentation errors
 *
 * Specifically used in {@link Converter::checkKillClass()}
 */
 var $killclass = array();
 /**
 * array of methods by package and class
 *
 * format:<pre>
 * array(packagename =>
 *         array(classname =>
 *               array(methodname1 => {@link parserMethod} class,
 *                     methodname2 => {@link parserMethod} class,...)
 *                      )
 *              )
 *      )</pre>
 * @var array
 * @see Converter
 */
 var $methods = array();
 
 /**
 * array of class variables by package and class
 *
 * format:<pre>
 * array(packagename =>
 *         array(classname =>
 *                array(variablename1 => {@link parserVar} class,
 *                      variablename2 => {@link parserVar} class,...
 *                     )
 *              )
 *      )</pre>
 * @var array
 * @see Converter
 */
 var $vars = array();
 
 /**
 * array of class variables by package and class
 *
 * format:<pre>
 * array(packagename =>
 *         array(classname =>
 *                array(constname1 => {@link parserConst} class,
 *                      constname2 => {@link parserConst} class,...
 *                     )
 *              )
 *      )</pre>
 * @var array
 * @see Converter
 */
 var $consts = array();
 /**
 * Reverse class_packages_by_file, used to prevent duplicates
 * @var array Format: array(packagename => 1)
 */
 var $revcpbf = array();
 /**
 * All classes with no parents (no extends clause) are tracked in this array
 * by the file that contains them.
 *
 * Format:<pre>
 * array(
 *     classname => array(
 *         name of file1 that contains root classname,
 *         name of file2 that contains root classname,
 *         ...
 *     )
 * )</pre>
 * @var array
 */
 var $roots = array();
 /**
 * All classes with a parent that was not parsed are included in this array
 *
 * Format:<pre>
 * array(
 *     classname => array(
 *         name of file1 that contains root classname,
 *         name of file2 that contains root classname,
 *         ...
 *     )
 * )</pre>
 * @var array
 */
 var $specialRoots = array();
 
 /**
 * array of all files that contain classes with the same name
 * @var array Format: (classname => array(path1, path2,...))
 */
 var $potentialclassconflicts = array();
 
 /**
 * array of all inter-package name conflicts of classes
 *
 * This array allows documentation of PHP namespace conflicts that would
 * occur should a user try to include these files in the same file
 * @var array Format: (classname => array(path1, path2,...))
 */
 var $classconflicts = array();
 /**#@-*/
 /**
 * While parsing, add a class to the list of parsed classes
 *
 * sets up the {@link $classesbyfile, $classesbynamefile, $extendsbyfile},
 * {@link $classchildrenbyfile, $roots} arrays, and sets {@link $curclass}
 *
 * @param parserClass &$element element is a {@link parserClass}
 *
 * @return void
 * @uses addPackageToFile() marks the current class's package as being
 *                          present in a file
 */
 function addClass(&$element)
 {
 $this->curclass   = $element->getName();
 $element->curfile = $this->curfile;
 if (isset($this->classesbyfile[$this->curfile][$this->curclass])) {
 addWarning(PDERROR_ELEMENT_IGNORED,
 'class', $this->curclass, $this->curfile);
 $this->curclass = false;
 return;
 }
 $this->
 classesbyfile
 [$this->curfile][$this->curclass]
 = $element;
 $this->
 classesbynamefile[$this->curclass][]
 = $this->curfile;
 $this->
 extendsbyfile[$this->curfile][$this->curclass]
 = $element->getExtends();
 $this->
 classchildrenbyfile[$element->getExtends()]
 [$this->curfile][$this->curclass][]
 = $element->docblock->package;
 if ($element->docblock->getExplicitPackage())
 $this->addPackageToFile($element->docblock->package);
 if (!$element->getExtends()) {
 $this->roots[$this->curclass][] = $this->curfile;
 }
 }
 
 /**
 * While parsing, add a method to the list of parsed methods
 *
 * sets up the {@link $methodsbyfile} array using {@link $curfile} and
 * {@link $curclass}
 *
 * @param parserMethod &$element element is a {@link parserMethod}
 *
 * @return void
 */
 function addMethod(&$element)
 {
 if (!$this->curclass) return;
 $this->methodsbyfile[$this->curfile][$this->curclass][] = $element;
 }
 
 /**
 * While parsing, add a variable to the list of parsed variables
 *
 * sets up the {@link $varsbyfile} array using {@link $curfile}
 * and {@link $curclass}
 *
 * @param parserVar &$element element is a {@link parserVar}
 *
 * @return void
 */
 function addVar(&$element)
 {
 if (!$this->curclass) return;
 $this->varsbyfile[$this->curfile][$this->curclass][] = $element;
 }
 
 /**
 * While parsing, add a variable to the list of parsed variables
 *
 * sets up the {@link $constsbyfile} array using {@link $curfile}
 * and {@link $curclass}
 *
 * @param parserConst &$element element is a {@link parserConst}
 *
 * @return void
 */
 function addConst(&$element)
 {
 if (!$this->curclass) return;
 $this->constsbyfile[$this->curfile][$this->curclass][] = $element;
 }
 
 /**
 * Prepare to parse a new file
 *
 * sets {@link $curfile} to $file and {@link $curclass}
 * to false (no class being parsed)
 *
 * @param string $file file currently being parsed
 *
 * @return void
 */
 function nextFile($file)
 {
 $this->curfile  = $file;
 $this->curclass = false;
 }
 
 /**
 * Mark a package as being used in a class
 *
 * {@source}
 *
 * @param string $package package name
 *
 * @return void
 */
 function addPackageToFile($package)
 {
 if (!isset($this->revcpbf[$this->curfile][$package]))
 $this->classpackagebyfile[$this->curfile][] = $package;
 $this->revcpbf[$this->curfile][$package]    = 1;
 }
 
 /**
 * Find the parent class of $class, and set up structures to note this fact
 *
 * Modifies the {@link parserClass} element in {@link $classesbyfile} to use
 * the parent's package, and inherit methods/vars
 *
 * @param string $class child class to find parent class
 * @param string $file  file child class is located in
 *
 * @return void
 * @uses $definitechild if a match is made between a parent class and parameter
 *                      $class in file $file, then definitechild is set here
 * @uses getParentClass() to find the parent class
 */
 function setClassParent($class,$file)
 {
 if (is_array($par = $this->getParentClass($class, $file))) {
 // (for debugging)
 // phpDocumentor_out("$file class $class extends "
 //    . $par[1] ." file ". $par[0] . "\n");
 
 $this->classesbyfile[$file][$class]->setParent($par[1], $par[0], $this);
 $this->definitechild[$par[1]][$par[0]][$class] = $file;
 } else {
 $this->classesbyfile[$file][$class]->setParentNoClass($par);
 }
 }
 
 /**
 * Main processing engine for setting up class inheritance.
 *
 * This function uses {@link $roots} to traverse the inheritance tree via
 * {@link processChild()} and returns the data structures
 * phpDocumentor_IntermediateParser needs to convert parsed data
 * to output using {@link phpDocumentor_IntermediateParser::Convert()}
 *
 * @param phpDocumentor_IntermediateParser &$render the renderer object
 *
 * @return void
 * @uses processChild() set up inheritance
 * @todo CS Cleanup - rename to "inherit" for CamelCaps naming standard
 */
 function Inherit(&$render)
 {
 phpDocumentor_out("\nProcessing Class Inheritance\n\n");
 flush();
 phpDocumentor_out("\nProcessing Root Trees\n\n");
 flush();
 foreach ($this->roots as $class => $files) {
 for ($i=0; $i<count($files); $i++) {
 $this->processChild($render, $class, $files[$i]);
 }
 }
 if (0)
 foreach ($this->classesbyfile as $i => $j) {
 foreach ($j as $k => $m) {
 var_dump($i, $k);
 if ($i == 'iConverter') {
 var_dump($j);
 }
 }
 }
 phpDocumentor_out("\nProcessing leftover classes "
 . "(classes that extend root classes not found in the same package)\n");
 flush();
 foreach ($this->classesbyfile as $i => $j) {
 foreach ($j as $k => $m) {
 $this->processChild($render, $k, $i, true);
 }
 }
 phpDocumentor_out("done processing leftover classes\n");
 flush();
 $this->setupClassConflicts();
 }
 
 /**
 * Transfers actual conflicts from {@link $potentialClassconflicts} to
 * {@link $classconflicts}
 *
 * @return void
 * @access private
 * @uses $potentialclassconflicts transfers values to {@link $classconflicts}
 */
 function setupClassConflicts()
 {
 foreach ($this->potentialclassconflicts as $class => $paths) {
 if (count($paths) - 1) { //conflict
 $package = array();
 foreach ($paths as $path) {
 // create a list of conflicting classes in each package
 if (isset($this->classpathpackages[$class][$path]))
 $package[$this->classpathpackages[$class][$path][0]][] = $path;
 }
 foreach ($package as $pathpackages) {
 /*
 * if at least 2 functions exist in the same package,
 * delete all but the first one and add warnings
 */
 if (count($pathpackages) - 1) {
 for ($i=1; $i < count($pathpackages); $i++) {
 if (isset($this->classesbyfile[$pathpackages[$i]])) {
 addWarning(PDERROR_ELEMENT_IGNORED,
 'class', $class, $pathpackages[$i]);
 $this->killClass($class, $pathpackages[$i]);
 $oth = array_flip($paths);
 unset($paths[$oth[$pathpackages[$i]]]);
 }
 }
 }
 }
 $this->classconflicts[$class] = $paths;
 }
 }
 }
 
 /**
 * If a package contains two classes with the same name, this function finds
 * that conflict
 *
 * Returns the {@link $classconflicts} entry for class $class, minus its own path
 *
 * @param mixed $class the class name to search for
 *
 * @return mixed returns false if no conflicts,
 *               or an array of paths containing conflicts
 */
 function getConflicts($class)
 {
 if (!isset($this->classconflicts[$class])) return false;
 $a = array();
 foreach ($this->classconflicts[$class] as $conflict) {
 $a[$this->classesbyfile[$conflict][$class]->docblock->package]
 = $this->classesbyfile[$conflict][$class];
 }
 return $a;
 }
 
 /**
 * sets up {@link $killclass} for use by Converter::checkKillClass()
 *
 * @param mixed $class the class
 * @param mixed $path  the path
 *
 * @return void
 * @access private
 */
 function killClass($class,$path)
 {
 $this->killclass[$class][$path] = true;
 }
 
 /**
 * This function recursively climbs up the class tree, setting inherited
 * information like package and adds the elements to
 * {@link phpDocumentor_IntermediateParser}.
 *
 * Using structures defined in {@link Classes},
 * the function first sets package information,
 * and then seeks out child classes.
 * It uses 3 tests to determine whether a class is a child class.
 * <ol>
 *    <li>child class is in the same file as the parent class
 *        and extends parent class
 *    </li>
 *    <li>child class is in a different file and specifies
 *        the parent's @package in its docblock
 *    </li>
 *    <li>child class is in a different file and is in a
 *        different @package, with one possible parent class
 *    </li>
 * </ol>
 *
 * @param phpDocumentor_IntermediateParser &$render the renderer object
 * @param string                           $class   class to process
 * @param string                           $file    name of file $class
 *                                                  is located in
 * @param boolean                          $furb    flag used privately
 *                                                  to control informational
 *                                                  output while parsing
 *                                                  (used when processing
 *                                                  leftover classes in
 *                                                  {@link Inherit()}
 *
 * @return void
 * @global string default package, usually "default"
 */
 function processChild(&$render,$class,$file,$furb = false)
 {
 global $phpDocumentor_DefaultPackageName;
 if (isset($this->classesbyfile[$file][$class]->processed))
 return;
 $this->potentialclassconflicts[$class][] = $file;
 if ($furb)
 phpDocumentor_out("Processing $class in file $file\n");
 flush();
 $this->classesbyfile[$file][$class]->processed = true;
 
 $db = $this->classesbyfile[$file][$class];
 $render->addUses($db, $file);
 if (!$render->parsePrivate) {
 /*
 * if this class has an @access private,
 * and parse private is disabled, remove it
 */
 if ($db->docblock->hasaccess) {
 $aaa = $db->docblock->getKeyword('access');
 if (is_object($aaa) && $aaa->getString() == 'private') {
 if (isset($this->varsbyfile[$file])
 && isset($this->varsbyfile[$file][$class])) {
 unset($this->varsbyfile[$file][$class]);
 }
 if (isset($this->methodsbyfile[$file])
 && isset($this->methodsbyfile[$file][$class])) {
 unset($this->methodsbyfile[$file][$class]);
 }
 if (isset($this->constsbyfile[$file])
 && isset($this->constsbyfile[$file][$class])) {
 unset($this->constsbyfile[$file][$class]);
 }
 $this->classesbyfile[$file][$class]->ignore = true;
 // if this is a root class, remove it from the roots array
 if (isset($this->roots[$class])) {
 foreach ($this->roots[$class] as $i => $files) {
 // find the file key and unset
 if ($files == $file)
 unset($this->roots[$class][$i]);
 }
 }
 /*
 * if this is a child, remove it from the list
 * of child classes of its parent
 */
 if ($db->getExtends())
 unset($this->classchildrenbyfile[$db->getExtends()][$file]);
 return;
 }
 }
 }
 if ($render->packageoutput) {
 if (!in_array($db->docblock->package, $render->packageoutput)) {
 if (isset($this->varsbyfile[$file])
 && isset($this->varsbyfile[$file][$class])) {
 unset($this->varsbyfile[$file][$class]);
 }
 if (isset($this->methodsbyfile[$file])
 && isset($this->methodsbyfile[$file][$class])) {
 unset($this->methodsbyfile[$file][$class]);
 }
 if (isset($this->constsbyfile[$file])
 && isset($this->constsbyfile[$file][$class])) {
 unset($this->constsbyfile[$file][$class]);
 }
 $this->classesbyfile[$file][$class]->ignore = true;
 if (isset($this->roots[$class])) {
 foreach ($this->roots[$class] as $i => $files) {
 if ($files == $file) unset($this->roots[$class][$i]);
 }
 }
 if ($db->getExtends())
 unset($this->classchildrenbyfile[$db->getExtends()][$file]);
 return;
 }
 }
 $this->setClassParent($class, $file);
 $db = $this->classesbyfile[$file][$class];
 if ($furb && !is_array($db->parent)) {
 // debug("furb adding $class $file to roots");
 $this->specialRoots[$db->parent][] = array($class, $file);
 }
 // fix for 591396
 if (!$db->docblock->getExplicitPackage()) {
 $a = $render->proceduralpages->pagepackages[$file];
 if ($a[0] != $phpDocumentor_DefaultPackageName) {
 // inherit page package
 $this->classesbyfile[$file][$class]->docblock->package = $a[0];
 }
 }
 if ($this->classesbyfile[$file][$class]->docblock->package
 == $render->proceduralpages->pagepackages[$file][0]) {
 if ($this->classesbyfile[$file][$class]->docblock->subpackage == '') {
 $this->classesbyfile[$file][$class]->docblock->subpackage
 = $render->proceduralpages->pagepackages[$file][1];
 }
 }
 $db = $this->classesbyfile[$file][$class];
 $render->addPackageParent($db);
 $render->addPageIfNecessary($file, $db);
 if ($access = $db->docblock->getKeyword('access')) {
 if (!is_string($access) && is_object($access))
 $access = $access->getString();
 if (!is_string($access))
 $access = 'public';
 if (($access == 'private') && (!$render->parsePrivate)) {
 if (isset($this->varsbyfile[$file])
 && isset($this->varsbyfile[$file][$class])) {
 foreach ($this->varsbyfile[$file][$class] as $i => $vr) {
 $vr->docblock->addKeyword('access', 'private');
 $this->varsbyfile[$file][$class][$i] = $vr;
 }
 }
 if (isset($this->methodsbyfile[$file])
 && isset($this->methodsbyfile[$file][$class])) {
 foreach ($this->methodsbyfile[$file][$class] as $i => $vr) {
 $vr->docblock->addKeyword('access', 'private');
 $this->methodsbyfile[$file][$class][$i] = $vr;
 }
 }
 if (isset($this->constsbyfile[$file])
 && isset($this->constsbyfile[$file][$class])) {
 foreach ($this->constsbyfile[$file][$class] as $i => $vr) {
 $vr->docblock->addKeyword('access', 'private');
 $this->constsbyfile[$file][$class][$i] = $vr;
 }
 }
 }
 }
 $this->classpathpackages[$class][$file]
 = array($db->docblock->package,$db->docblock->subpackage);
 if ($db->docblock->getExplicitPackage()) {
 $render->proceduralpages->
 addClassPackageToFile($file,
 $db->docblock->package, $db->docblock->subpackage);
 }
 $render->addElementToPage($db, $file);
 if (isset($this->varsbyfile[$file])
 && isset($this->varsbyfile[$file][$class])) {
 foreach ($this->varsbyfile[$file][$class] as $i => $vr) {
 $vr->docblock->package    = $db->docblock->package;
 $vr->docblock->subpackage = $db->docblock->subpackage;
 $render->addElementToPage($vr, $file);
 $render->addUses($vr, $file);
 $this->varsbyfile[$file][$class][$i]                        = $vr;
 $this->vars[$db->docblock->package][$class][$vr->getName()] = $vr;
 }
 }
 if (isset($this->methodsbyfile[$file])
 && isset($this->methodsbyfile[$file][$class])) {
 foreach ($this->methodsbyfile[$file][$class] as $i => $vr) {
 $vr->docblock->package    = $db->docblock->package;
 $vr->docblock->subpackage = $db->docblock->subpackage;
 $render->addElementToPage($vr, $file);
 $render->addUses($vr, $file);
 $this->methodsbyfile[$file][$class][$i]                        = $vr;
 $this->methods[$db->docblock->package][$class][$vr->getName()] = $vr;
 }
 }
 if (isset($this->constsbyfile[$file])
 && isset($this->constsbyfile[$file][$class])) {
 foreach ($this->constsbyfile[$file][$class] as $i => $vr) {
 $vr->docblock->package    = $db->docblock->package;
 $vr->docblock->subpackage = $db->docblock->subpackage;
 $render->addElementToPage($vr, $file);
 $render->addUses($vr, $file);
 $this->constsbyfile[$file][$class][$i]                         = $vr;
 $this->methods[$db->docblock->package][$class][$vr->getName()] = $vr;
 }
 }
 $this->classpackages[$class][]
 = array($db->docblock->package,$db->docblock->subpackage);
 if (is_array($db->parent))
 $this->classparents[$db->docblock->package][$class] = $db->parent[1];
 else
 $this->classparents[$db->docblock->package][$class] = $db->getExtends();
 if (is_array($db->parent)) {
 $z = $this->getClass($db->parent[1], $db->parent[0]);
 
 $this->classchildren[$z->docblock->package][$db->parent[1]][] = $db;
 }
 if (isset($this->classchildrenbyfile[$class])) {
 foreach ($this->classchildrenbyfile[$class] as $childfile => $other) {
 // test 1, inherits in same file (must be same package)
 if ($childfile == $file) {
 foreach ($other as $child => $packages) {
 // debug("parent $class same file $child");
 $this->processChild($render, $child, $childfile);
 $x = $this->getClass($child, $childfile);
 if ($x->docblock->package
 != $GLOBALS['phpDocumentor_DefaultPackageName']) {
 // child package need root for class trees
 if ($x->docblock->package != $db->docblock->package) {
 // debug("adding $child in $childfile 1");
 $this->roots[$child][] = $childfile;
 }
 }
 }
 } else {
 // test 2, different file, same package
 foreach ($other as $child => $packages) {
 for ($j=0; $j<count($packages); $j++) {
 if ($this->classesbyfile[$file][$class]->
 docblock->package == $packages[$j]) {
 $this->processChild($render, $child, $childfile);
 // debug("$childfile diff file $child, parent $class,
 //     same package ".$packages[$j]);
 } else {
 /*
 * test 3, different file, different package,
 * only 1 parent is possible
 */
 if (isset($this->classesbynamefile[$child])) {
 // 1 possible parent
 if (count($this->classesbynamefile[$class])
 == 1) {
 // debug("$childfile diff file $child,
 //        diff package,
 //        1 possible parent root $class");
 $this->processChild($render,
 $child, $childfile);
 $x = $this->getClass($child, $childfile);
 if ($x->docblock->package
 != $GLOBALS
 ['phpDocumentor_DefaultPackageName']) {
 // child package need root
 //for class trees
 if ($x->docblock->package
 != $db->docblock->package) {
 // debug("adding roots
 // $child in $childfile 2");
 $this->roots[$child][] = $childfile;
 }
 }
 }
 }
 }
 }
 }
 }
 }
 }
 }
 
 /**
 * Get the parserClass representation of a class from its name and file
 *
 * @param string $class classname
 * @param string $file  file classname is located in
 *
 * @return parserClass
 */
 function &getClass($class, $file)
 {
 // debug("getClass called with class $class file $file");
 return $this->classesbyfile[$file][$class];
 }
 
 /**
 * Used by {@link parserData::getClasses()}
 * to retrieve classes defined in file $path
 *
 * retrieves the array entry from {@link $classesbyfile} for $path
 *
 * @param string $path full path to filename
 *
 * @return mixed returns false if no classes defined in the file,
 *               otherwise returns an array of {@link parserClass}es
 */
 function getClassesInPath($path)
 {
 if (!isset($this->classesbyfile[$path])) return false;
 return $this->classesbyfile[$path];
 }
 
 /**
 * called by {@link parserClass::hasMethods()}.  Should not be directly called
 *
 * @param string $file  file classname is located in
 * @param string $class classname
 *
 * @return bool
 * @access private
 */
 function hasMethods($file, $class)
 {
 return isset($this->methodsbyfile[$file][$class]);
 }
 
 /**
 * called by {@link parserClass::hasConsts()}.
 * Should not be directly called
 *
 * @param string $file  file classname is located in
 * @param string $class classname
 *
 * @return bool
 * @access private
 */
 function hasConsts($file,$class)
 {
 return isset($this->constsbyfile[$file][$class]);
 }
 
 /**
 * called by {@link parserClass::hasVars()}.  Should not be directly called
 *
 * @param string $file  file classname is located in
 * @param string $class classname
 *
 * @return bool
 * @access private
 */
 function hasVars($file, $class)
 {
 return isset($this->varsbyfile[$file][$class]);
 }
 
 /**
 * called by {@link parserClass::hasMethod()}.  Should not be directly called
 *
 * @param string $class classname
 * @param string $file  file classname is located in
 * @param string $name  method name
 *
 * @return bool
 * @access private
 */
 function hasMethod($class, $file, $name)
 {
 if (!$this->hasMethods($file, $class)) return false;
 for ($i=0; $i<count($this->methodsbyfile[$file][$class]); $i++) {
 if ($this->methodsbyfile[$file][$class][$i]->getName() == $name)
 return true;
 }
 return false;
 }
 
 /**
 * called by {@link parserClass::hasVar()}.  Should not be directly called
 *
 * @param string $class classname
 * @param string $file  file classname is located in
 * @param string $name  var name
 *
 * @return bool
 * @access private
 */
 function hasVar($class, $file, $name)
 {
 if (!$this->hasVars($file, $class)) return false;
 for ($i=0; $i<count($this->varsbyfile[$file][$class]); $i++) {
 if ($this->varsbyfile[$file][$class][$i]->getName() == $name)
 return true;
 }
 return false;
 }
 
 /**
 * called by {@link parserClass::hasConst()}.  Should not be directly called
 *
 * @param string $class classname
 * @param string $file  file classname is located in
 * @param string $name  constant name
 *
 * @return bool
 * @access private
 */
 function hasConst($class, $file, $name)
 {
 if (!$this->hasConsts($file, $class)) return false;
 for ($i=0; $i<count($this->constsbyfile[$file][$class]); $i++) {
 if ($this->constsbyfile[$file][$class][$i]->getName() == $name)
 return true;
 }
 return false;
 }
 
 /**
 * called by {@link parserClass::getMethods()}.  Should not be directly called
 *
 * @param string $class classname
 * @param string $file  file classname is located in
 *
 * @return mixed
 * @access private
 */
 function &getMethods($class, $file)
 {
 if (!isset($this->methodsbyfile[$file][$class])) {
 $flag = false;
 return $flag;
 }
 return $this->methodsbyfile[$file][$class];
 }
 
 /**
 * called by {@link parserClass::getVars()}.  Should not be directly called
 *
 * @param string $class classname
 * @param string $file  file classname is located in
 *
 * @return mixed
 * @access private
 */
 function &getVars($class, $file)
 {
 if (!isset($this->varsbyfile[$file][$class])) {
 $flag = false;
 return $flag;
 }
 return $this->varsbyfile[$file][$class];
 }
 
 /**
 * called by {@link parserClass::getConsts()}.  Should not be directly called
 *
 * @param string $class classname
 * @param string $file  file classname is located in
 *
 * @return mixed
 * @access private
 */
 function &getConsts($class, $file)
 {
 if (!isset($this->constsbyfile[$file][$class])) {
 $flag = false;
 return $flag;
 }
 return $this->constsbyfile[$file][$class];
 }
 
 /**
 * called by {@link parserClass::getMethod()}.  Should not be directly called
 *
 * @param string $class classname
 * @param string $file  file classname is located in
 * @param string $name  method name
 *
 * @return mixed
 * @access private
 */
 function getMethod($class, $file, $name)
 {
 if (!$this->hasMethod($class, $file, $name)) return false;
 for ($i=0; $i<count($this->methodsbyfile[$file][$class]); $i++) {
 if ($this->methodsbyfile[$file][$class][$i]->getName() == $name)
 return $this->methodsbyfile[$file][$class][$i];
 }
 }
 
 /**
 * called by {@link parserClass::getVar()}.  Should not be directly called
 *
 * @param string $class classname
 * @param string $file  file classname is located in
 * @param string $name  var name
 *
 * @return mixed
 * @access private
 */
 function getVar($class, $file, $name)
 {
 if (!$this->hasVar($class, $file, $name)) return false;
 for ($i=0; $i<count($this->varsbyfile[$file][$class]); $i++) {
 if ($this->varsbyfile[$file][$class][$i]->getName() == $name)
 return $this->varsbyfile[$file][$class][$i];
 }
 }
 
 /**
 * called by {@link parserClass::getConst()}.  Should not be directly called
 *
 * @param string $class classname
 * @param string $file  file classname is located in
 * @param string $name  const name
 *
 * @return mixed
 * @access private
 */
 function getConst($class, $file, $name)
 {
 if (!$this->hasConst($class, $file, $name)) return false;
 for ($i=0; $i<count($this->constsbyfile[$file][$class]); $i++) {
 if ($this->constsbyfile[$file][$class][$i]->getName() == $name)
 return $this->constsbyfile[$file][$class][$i];
 }
 }
 
 /**
 * Search for a class in a package
 *
 * @param string $class   classname
 * @param string $package package classname is in
 *
 * @return mixed returns false if no class in $package,
 *               otherwise returns a {@link parserClass}
 */
 function &getClassByPackage($class, $package)
 {
 if (!isset($this->classesbynamefile[$class])) {
 // removed, too many warnings, not very useful
 // addWarning(PDERROR_CLASS_NOT_IN_PACKAGE,$class,$package);
 
 $flag = false;
 return $flag;
 }
 for ($i=0; $i < count($this->classesbynamefile[$class]); $i++) {
 $cls =
 $this->classesbyfile[$this->classesbynamefile[$class][$i]][$class];
 $pkg = $cls->getPackage();
 if ($pkg == $package)
 return $cls;
 }
 // addWarning(PDERROR_CLASS_NOT_IN_PACKAGE,$class,$package);
 
 $flag = false;
 return $flag;
 }
 
 /**
 * Find the parent class of a class in file $file
 * uses 3 tests to find the parent classname:
 * <ol>
 *    <li>only one class with the parent classname</li>
 *    <li>more than one class, but only one in the same file as the child</li>
 *    <li>only one parent class in the same package as the child</li>
 * </ol>
 *
 * @param string $class classname
 * @param string $file  file classname is located in
 *
 * @return mixed false if no parent class,
 *               a string if no parent class found by that name,
 *               and an array(file parentclass is in, parentclassname)
 */
 function getParentClass($class,$file)
 {
 if (!isset($this->classesbyfile[$file][$class])) {
 return false;
 }
 $element = $this->classesbyfile[$file][$class];
 if (!($ex = $element->getExtends())) return false;
 // first check to see if there is one and only one
 // class with the parent class's name
 if (isset($this->classesbynamefile[$ex])) {
 if (count($this->classesbynamefile[$ex]) == 1) {
 if ($this->classesbyfile
 [$this->classesbynamefile[$ex][0]][$ex]->ignore) {
 return $ex;
 }
 return array($this->classesbynamefile[$ex][0],$ex);
 } else {
 // next check to see if there is a parent class in the same file
 if (isset($this->classesbyfile[$file][$ex])) {
 if ($this->classesbyfile[$file][$ex]->ignore) {
 return $ex;
 }
 return array($file,$ex);
 }
 // next check to see if there is only one package
 // used in the file, try to resolve it that way
 if (isset($this->classpackagebyfile[$file])) {
 if (count($this->classpackagebyfile[$file]) == 1) {
 for ($i=0;$i<count($this->classesbynamefile[$ex]);$i++) {
 if ($this->classesbyfile
 [$this->classesbynamefile[$ex][$i]][$ex]->getPackage()
 == $this->classpackagebyfile[$file][0]) {
 if ($this->classesbyfile
 [$this->classesbynamefile[$ex][$i]][$ex]->ignore)
 return $ex;
 return array($this->classesbynamefile[$ex][$i],$ex);
 }
 }
 }
 }
 // name conflict
 addWarning(PDERROR_INHERITANCE_CONFLICT, $class, $file, $ex);
 return $ex;
 }
 } else {
 if (class_exists('ReflectionClass') && class_exists($ex)) {
 $r = new ReflectionClass($ex);
 if ($r->isInternal()) {
 return $ex; // no warning
 }
 }
 addWarning(PDERROR_PARENT_NOT_FOUND, $class, $ex);
 return $ex;
 }
 }
 
 /**
 * Get a list of all root classes indexed by package.  Used to generate
 * class trees by {@link Converter}
 *
 * @param boolean $all [since phpDocumentor 1.3.0RC6] determines whether to
 *                     return class trees that extend non-parsed classes
 *
 * @return array array(package => array(rootclassname, rootclassname,...),...)
 */
 function getRoots($all = false)
 {
 $roots     = array();
 $temproots = $this->roots;
 if (!$all) {
 foreach ($this->specialRoots as $package => $root) {
 foreach ($root as $parent => $info) {
 $temproots[$info[0]][] = $info[1];
 }
 }
 }
 foreach ($temproots as $class => $files) {
 if (count($files)) {
 foreach ($files as $i => $boofou) {
 $x = $this->getClass($class, $files[$i]);
 
 $roots[$x->getPackage()][] = $class;
 }
 }
 }
 foreach ($roots as $package => $root) {
 usort($roots[$package], "strnatcasecmp");
 }
 if ($all) {
 $specialRoots = array();
 foreach ($this->specialRoots as $parent => $classinfo) {
 if (count($classinfo)) {
 foreach ($classinfo as $i => $info) {
 $x = $this->getClass($info[0], $info[1]);
 
 $specialRoots[$x->getPackage()][$parent][] = $info[0];
 }
 }
 }
 foreach ($specialRoots as $package => $root) {
 uksort($specialRoots[$package], "strnatcasecmp");
 foreach ($specialRoots[$package] as $parent => $classes) {
 usort($specialRoots[$package][$parent], 'strnatcasecmp');
 }
 }
 return array('special' => $specialRoots, 'normal' => $roots);
 }
 return $roots;
 }
 
 /**
 * Get all classes confirmed in parsing
 * to be descended class $parclass in file $file
 *
 * @param string $parclass name of parent class
 * @param string $file     file parent class is found in
 *
 * @return mixed either false if no children, or array of format
 *         array(childname => childfile,childname2 => childfile2,...)
 * @see parserClass::getChildClassList()
 * @uses $definitechild
 */
 function getDefiniteChildren($parclass, $file)
 {
 if (isset($this->definitechild[$parclass][$file]))
 return $this->definitechild[$parclass][$file];
 return false;
 }
 }
 ?>
 
 |