home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / php / PEAR / PhpDocumentor / phpDocumentor / ParserDocBlock.inc < prev    next >
Encoding:
Text File  |  2008-07-02  |  36.3 KB  |  1,226 lines

  1. <?php
  2. /**
  3.  * DocBlock Parser Classes
  4.  * 
  5.  * phpDocumentor :: automatic documentation generator
  6.  * 
  7.  * PHP versions 4 and 5
  8.  *
  9.  * Copyright (c) 2002-2006 Gregory Beaver
  10.  * 
  11.  * LICENSE:
  12.  * 
  13.  * This library is free software; you can redistribute it
  14.  * and/or modify it under the terms of the GNU Lesser General
  15.  * Public License as published by the Free Software Foundation;
  16.  * either version 2.1 of the License, or (at your option) any
  17.  * later version.
  18.  * 
  19.  * This library is distributed in the hope that it will be useful,
  20.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  22.  * Lesser General Public License for more details.
  23.  * 
  24.  * You should have received a copy of the GNU Lesser General Public
  25.  * License along with this library; if not, write to the Free Software
  26.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  27.  *
  28.  * @package    phpDocumentor
  29.  * @subpackage ParserDocBlock
  30.  * @author     Gregory Beaver <cellog@php.net>
  31.  * @copyright  2002-2006 Gregory Beaver
  32.  * @license    http://www.opensource.org/licenses/lgpl-license.php LGPL
  33.  * @version    CVS: $Id: ParserDocBlock.inc,v 1.12 2007/04/19 20:20:57 ashnazg Exp $
  34.  * @link       http://www.phpdoc.org
  35.  * @link       http://pear.php.net/PhpDocumentor
  36.  * @see        Parser, WordParser
  37.  * @since      1.0rc1
  38.  */
  39. /**
  40.  * represents a short or long description in a DocBlock ({@link parserDocBlock})
  41.  * @package phpDocumentor
  42.  * @subpackage ParserDocBlock
  43.  * @author Greg Beaver <cellog@php.net>
  44.  * @since 1.0rc1
  45.  * @version $Id: ParserDocBlock.inc,v 1.12 2007/04/19 20:20:57 ashnazg Exp $
  46.  */
  47. class parserDesc extends parserStringWithInlineTags
  48. {
  49.     /**
  50.      * Type is used by many functions to skip the hassle of if phpDocumentor_get_class($blah) == 'parserBlah'
  51.      * always '_desc'
  52.      * @var string
  53.      */
  54.     var $type = '_desc';
  55.     
  56.     /**
  57.      * @param mixed like {@link parserStringWithInlineTags::add()}, this can be a string or parserInlineTag, but it can also be a
  58.      *              parserStringWithInlineTags, and the contents will be merged
  59.      */
  60.     function add($stringOrClass)
  61.     {
  62.         if (is_object($stringOrClass))
  63.         {
  64.             if (phpDocumentor_get_class($stringOrClass) == 'parserstringwithinlinetags' ||
  65.                 phpDocumentor_get_class($stringOrClass) == 'parserdesc')
  66.             {
  67.                 for($i=0;$i<count($stringOrClass->value);$i++)
  68.                 {
  69.                     parserStringWithInlineTags::add($stringOrClass->value[$i]);
  70.                 }
  71.             } else
  72.             {
  73.                 parserStringWithInlineTags::add($stringOrClass);
  74.             }
  75.         } else return parserStringWithInlineTags::add($stringOrClass);
  76.     }
  77.     
  78.     /**
  79.      * @return boolean whether this desc has an {@}inheritdoc} inline tag
  80.      */
  81.     function hasInheritDoc()
  82.     {
  83.         for($i=0;$i<count($this->value);$i++)
  84.         {
  85.             if (phpDocumentor_get_class($this->value[$i])=='parserinheritdocinlinetag') return true;
  86.         }
  87.     }
  88.     
  89.     /**
  90.      * @return boolean whether this desc has an {@}source} inline tag
  91.      */
  92.     function hasSource()
  93.     {
  94.         for($i=0;$i<count($this->value);$i++)
  95.         {
  96.             if (phpDocumentor_get_class($this->value[$i])=='parsersourceinlinetag') return true;
  97.         }
  98.     }
  99.     
  100.     /**
  101.      * replaces {@}inheritdoc} with the contents of the parent DocBlock
  102.      * @param parserDesc parent parserDesc, used to retrieve the description
  103.      */
  104.     function replaceInheritDoc($desc)
  105.     {
  106.         $value = $this->value;
  107.         $this->value = array();
  108.         for($i=0;$i<count($value);$i++)
  109.         {
  110.             if (phpDocumentor_get_class($value[$i])=='parserinheritdocinlinetag')
  111.             {
  112.                 for($j=0;$j<count($desc->value);$j++)
  113.                 {
  114.                     $this->add($desc->value[$j]);
  115.                 }
  116.             } else $this->add($value[$i]);
  117.         }
  118.     }
  119. }
  120.  
  121. /**
  122.  * Represents a docblock and its components, {@link $desc}, {@link $sdesc}, {@link $tags}, and also {@link $params} for functions
  123.  * @package phpDocumentor
  124.  * @subpackage ParserDocBlock
  125.  * @author Greg Beaver <cellog@php.net>
  126.  * @since 1.0rc1
  127.  * @version $Id: ParserDocBlock.inc,v 1.12 2007/04/19 20:20:57 ashnazg Exp $
  128.  */
  129. class parserDocBlock
  130. {
  131.     /**
  132.      * @var parserDesc
  133.      */
  134.     var $desc = false;
  135.     /**
  136.      * @var array array of {@link parserDesc}s
  137.      */
  138.     var $processed_desc = false;
  139.     /**
  140.      * @var array array of {@link parserDesc}s
  141.      */
  142.     var $processed_sdesc = false;
  143.     /**
  144.      * @var parserDesc
  145.      */
  146.     var $sdesc = false;
  147.     /**
  148.      * Line number in the source on which this docblock begins
  149.      * @since 1.2
  150.      * @var false|integer
  151.      */
  152.     var $linenumber = false;
  153.     /**
  154.      * Line number in the source on which this docblock ends
  155.      * @since 1.2
  156.      * @var false|integer
  157.      */
  158.     var $endlinenumber = false;
  159.     /**
  160.      * array of {@link parserTag}s
  161.      * @var array
  162.      */
  163.     var $tags = array();
  164.     /**
  165.      * array of unrecognized {@link parserTag}s
  166.      * @var array
  167.      */
  168.     var $unknown_tags = array();
  169.     /**
  170.      * array of param data.
  171.      * Format:
  172.      * array(index of param in function parameter list -OR- parameter name =>
  173.      *         parserStringWithInlineTags,...)
  174.      * @var array
  175.      */
  176.     var $params = array();
  177.     /**
  178.      * array of global variable data.
  179.      * Format:
  180.      * array(index of global variable in @global tag list -OR- global variable name =>
  181.      *         array(datatype,parserStringWithInlineTags),...)
  182.      * @var array
  183.      */
  184.     var $funcglobals = array();
  185.     
  186.     /**
  187.      * array of static variable data.
  188.      * Format:
  189.      * array(index of static variable in @global tag list -OR- static variable name =>
  190.      *         {@link parserStaticvarTag},...)
  191.      * @var array
  192.      */
  193.     var $statics = array();
  194.     /**
  195.      * array of {@link parserPropertyTag}, {@link parserPropertyReadTag}, {@link parserPropertyWriteTag}, {@link parserMethodTag} magic tags
  196.      */
  197.     var $properties = array();
  198.     /**
  199.      * This is either a {@link parserReturnTag} or false if no return tag is present
  200.      * @var mixed
  201.      */
  202.     var $return = false;
  203.     /**
  204.      * This is either a {@link parserVarTag} or false if no var tag is present
  205.      * @var mixed
  206.      */
  207.     var $var = false;
  208.     /**
  209.      * fix for bug 591396
  210.      * @var boolean
  211.      */
  212.     var $explicitpackage = false;
  213.     /**
  214.      * fix for bug 708559
  215.      * @var boolean
  216.      */
  217.     var $explicitcategory = false;
  218.     /** @var string */
  219.     var $category;
  220.     /** @var string */
  221.     var $package = 'default';
  222.     /** @var string */
  223.     var $subpackage = '';
  224.     /**
  225.      * whether this DocBlock has an @access tag
  226.      * @var boolean */
  227.     var $hasaccess = false;
  228.     /**
  229.      * whether this DocBlock has a @name tag
  230.      * @var boolean */
  231.     var $hasname = false;
  232.     /**
  233.      * description of package parsed from @package tag
  234.      * Unused in this version
  235.      * @var string
  236.      */
  237.     var $packagedescrip = '';
  238.     /**
  239.      * description of subpackage parsed from @package tag
  240.      * Unused in this version
  241.      * @var string
  242.      */
  243.     var $subpackagedescrip = '';
  244.     /**
  245.      * Determines whether a DocBlock can legally have a {@}source} tag
  246.      * @tutorial tags.inlinesource.pkg
  247.      * @var boolean
  248.      * @access private
  249.      */
  250.     var $_canSource = false;
  251.     
  252.     /**
  253.      * sets package to default
  254.      * @global string default package name
  255.      */
  256.     function parserDocBlock()
  257.     {
  258.         global $phpDocumentor_DefaultPackageName;
  259.         $this->package = $GLOBALS['phpDocumentor_DefaultPackageName'];
  260.         $this->category = $GLOBALS['phpDocumentor_DefaultCategoryName'];
  261.     }
  262.     
  263.     /**
  264.      * Sets the starting line number for the DocBlock
  265.      * @param integer
  266.      */
  267.     function setLineNumber($number)
  268.     {
  269.         $this->linenumber = $number;
  270.     }
  271.     
  272.     /**
  273.      * Retrieve starting line number
  274.      * @return integer
  275.      */
  276.     function getLineNumber()
  277.     {
  278.         return $this->linenumber;
  279.     }
  280.     
  281.     /**
  282.      * Sets the ending line number for the DocBlock
  283.      * @param integer
  284.      */
  285.     function setEndLineNumber($number)
  286.     {
  287.         $this->endlinenumber = $number;
  288.     }
  289.     
  290.     /**
  291.      * Retrieve ending line number
  292.      * @return integer
  293.      */
  294.     function getEndLineNumber()
  295.     {
  296.         return $this->endlinenumber;
  297.     }
  298.     
  299.     /**
  300.      * Parse out any html tags from doc comments, and make them into
  301.      * abstract structures
  302.      * @uses parserDescParser::parse()
  303.      */
  304.     function postProcess()
  305.     {
  306.         if ($this->sdesc)
  307.         {
  308.             $parser = new parserDescParser;
  309.             $parser->subscribe('*',$this);
  310.             if ($this->desc) $parser->parse($this->desc->value);
  311.             $parser->parse($this->sdesc->value,true);
  312.         }
  313.     }
  314.     
  315.     /**
  316.      * Tells the DocBlock it can have a @filesource tag
  317.      *
  318.      * Only page-level DocBlocks may have a @filesource tag
  319.      */
  320.     function canSource()
  321.     {
  322.         $this->_canSource = true;
  323.     }
  324.     
  325.     /**
  326.      * Tells the DocBlock it can't have a @filesource tag
  327.      *
  328.      * Only page-level DocBlocks may have a @filesource tag
  329.      */
  330.     function cantSource()
  331.     {
  332.         $this->_canSource = false;
  333.     }
  334.     
  335.     /**
  336.      * Indirectly called after parsing by {@link postProcess}
  337.      *
  338.      * @param integer either 1 for long desc or 2 for short desc
  339.      * @param array data organized into paragraphs.  Each entry is a {@link parserStringWithInlineTags}
  340.      * @uses $processed_desc sets to the array passed from {@link parserDescParser::parse()}
  341.      * @uses $processed_sdesc sets to the array passed from {@link parserDescParser::parse()}
  342.      * @access private
  343.      */
  344.     function HandleEvent($event,$data)
  345.     {
  346.         if ($event == 1)
  347.         $this->processed_desc = $data;
  348.         else
  349.         $this->processed_sdesc = $data;
  350.     }
  351.     
  352.     /**
  353.      * @param array
  354.      */
  355.     function updateModifiers($modifiers)
  356.     {
  357.         if (is_array($modifiers) && count($modifiers))
  358.         {
  359.             foreach ($modifiers as $modifier)
  360.             {
  361.                 switch ($modifier)
  362.                 {
  363.                     case 'private' :
  364.                     case 'public' :
  365.                     case 'protected' :
  366.                         unset($this->tags['access']);
  367.                         $x = new parserAccessTag($modifier);
  368.                         if ($x->isvalid)
  369.                         {
  370.                             $this->hasaccess = true;
  371.                             $this->tags['access'][] = $x;
  372.                         }
  373.                     break;
  374.                     case 'static' :
  375.                     case 'abstract' :
  376.                         unset($this->tags[$modifier]);
  377.                         $this->addKeyword($modifier, '');
  378.                     break;
  379.                 }
  380.             }
  381.         }
  382.     }
  383.     
  384.     /**
  385.      * Set the short description of the DocBlock
  386.      *
  387.      * Setting the short description is possible by passing in one of three
  388.      * possible parameters:
  389.      * <ul>
  390.      *  <li>another DocBlock's short description</li>
  391.      *  <li>another DocBlock, the short description will be extracted</li>
  392.      *  <li>a Zend Studio-compatible @desc tag</li>
  393.      * </ul>
  394.      * @param parserDesc|parserDocBlock|parserTag sets {@link $sdesc}
  395.      */
  396.     function setShortDesc($desc)
  397.     {
  398.         if (phpDocumentor_get_class($desc) == 'parsertag')
  399.         {
  400.             $this->sdesc = new parserDesc;
  401.             $this->processed_sdesc = $desc->value;
  402.             return;
  403.         }
  404.         if (phpDocumentor_get_class($desc) == 'parserdesc') {
  405.             $this->sdesc = $desc;
  406.         } else
  407.         {
  408.             $this->sdesc = $desc->sdesc;
  409.             $this->processed_sdesc = $desc->processed_sdesc;
  410.         }
  411.         
  412.         if ($this->sdesc && $this->sdesc->hasSource())
  413.         {
  414.             addWarning(PDERROR_SOURCE_TAG_IGNORED,$this->sdesc->getString());
  415.         }
  416.     }
  417.     
  418.     /**
  419.      * Passes to {@link parserStringWithInlineTags::setSource()}
  420.      *
  421.      * After passing, it calls {@link postProcess()} to set up the new
  422.      * source
  423.      * @param string|array tokenized highlight-ready source code
  424.      * @param false|string name of class if this is a method source
  425.      */
  426.     function setSource($source, $class = false)
  427.     {
  428.         if ($this->desc)
  429.         {
  430.             $this->desc->setSource($source, $class);
  431.             $this->postProcess();
  432.         }
  433.     }
  434.     
  435.     /**
  436.      * @param parserDesc|parserDocBlock sets {@link $desc}
  437.      */
  438.     function setDesc($desc)
  439.     {
  440.         if (phpDocumentor_get_class($desc) == 'parserdesc')
  441.         $this->desc = $desc;
  442.         else
  443.         {
  444.             $this->desc = $desc->desc;
  445.             $this->processed_desc = $desc->processed_desc;
  446.         }
  447.     }
  448.     
  449.     /**
  450.      * Wrapper for {@link parserDesc::hasInheritDoc()}
  451.      * @return boolean
  452.      */
  453.     function hasInheritDoc()
  454.     {
  455.         if (!$this->desc) return false;
  456.         return $this->desc->hasInheritDoc();
  457.     }
  458.     
  459.     /**
  460.      * Wrapper for {@link parserDesc::replaceInheritDoc()}
  461.      *
  462.      * Also replaces {@}inheritdoc} in the {@link $processed_desc}
  463.      * @param parserDesc
  464.      */
  465.     function replaceInheritDoc($desc)
  466.     {
  467.         if (!$this->desc) return false;
  468.         $this->desc->replaceInheritDoc($desc->desc);
  469.         $this->postProcess();
  470.     }
  471.     
  472.     /**
  473.      * @param Converter takes {@link $sdesc} and converts it to a string and returns it if present, otherwise returns ''
  474.      * @return string
  475.      */
  476.     function getSDesc(&$converter)
  477.     {
  478.         if ($this->sdesc && $this->processed_sdesc)
  479.         {
  480.             $result = '';
  481.             foreach($this->processed_sdesc as $desc)
  482.             {
  483.                 if (count($desc->value))
  484.                 $result .= $desc->Convert($converter);
  485.             }
  486.             return $result;
  487.         } else
  488.         {
  489. //            var_dump($this->desc,$this->processed_desc);
  490.         }
  491.         return '';
  492.     }
  493.     
  494.     /**
  495.      * @param Converter takes {@link $desc} and converts it to a string and returns it if present, otherwise returns ''
  496.      * @return string
  497.      */
  498.     function getDesc(&$converter)
  499.     {
  500.         if ($this->desc && $this->processed_desc)
  501.         {
  502.             $result = '';
  503.             foreach($this->processed_desc as $desc)
  504.             {
  505.                 if (count($desc->value))
  506.                 $result .= $converter->EncloseParagraph($desc->Convert($converter));
  507.             }
  508.             return $result;
  509.         } else
  510.         {
  511. //            var_dump($this->desc,$this->processed_desc);
  512.         }
  513.         return '';
  514.     }
  515.     
  516.     /**
  517.      * @param string $paramVar if empty, param is indexed in the order received and set using {@link changeParam()}
  518.      * @param parserStringWithInlineTags $value
  519.      */
  520.     function addParam($paramVar, $paramType, $value)
  521.     {
  522.         if (empty($paramVar))
  523.         $this->params[count($this->params)] = new parserParamTag($paramType,$value);
  524.         else
  525.         $this->params[$paramVar] = new parserParamTag($paramType,$value);
  526.     }
  527.  
  528.     function resetParams()
  529.     {
  530.         $this->params = array();
  531.     }
  532.     /**
  533.      * @param integer $index index of parameter in the {@link $params} array
  534.      * @param string $name name of the parameter to set in the $params array
  535.      * @param string|null $type type of the parameter
  536.      */
  537.     function changeParam($index, $name, $type)
  538.     {
  539.         if ($name === $index) {
  540.             return;
  541.         }
  542.         $this->params[$name] = $this->params[$index];
  543.         unset($this->params[$index]);
  544.     }
  545.     
  546.     /**
  547.      * replaces nameless parameters in the {@link $params} array with their names
  548.      * add @param tags for params in the function with no entry
  549.      * @param array $params Format: array(parameter key =>
  550.      *                      array(0 => parameter name[,1 => default value][,2 => type hint]),...)
  551.      */
  552.     function updateParams($params)
  553.     {
  554.         $countparams = array_values($params);
  555.         reset($params);
  556.         for($i=0;$i<count($countparams);$i++, next($params))
  557.         {
  558.             if (isset($this->params[$i]))
  559.             {
  560.                 $info = current($params);
  561.                 $type = isset($info[2]) ? $info[2] : null;
  562.                 $this->changeParam($i, key($params), $type);
  563.                 $params[key($params)] = false;
  564.             }
  565.         }
  566.         $blank = new parserStringWithInlineTags;
  567.         foreach ($params as $key => $info) {
  568.             if (!$info) {
  569.                 continue;
  570.             }
  571.             $type = isset($info[2]) ? $info[2] : null;
  572.             if (!isset($this->params[$info[0]])) {
  573.                 $this->addParam($info[0], $type, $blank);
  574.             }
  575.         }
  576.         reset($params);
  577.         
  578.         if (isset($this->tags))
  579.         unset($this->tags['param']);
  580.     }
  581.     
  582.     /**
  583.      * Used to insert DocBlock Template tags into a docblock
  584.      * @param parserTag tag
  585.      * @global array used to determine whether to add ignored tags, or not
  586.      */
  587.     function addTag($tag)
  588.     {
  589.         global $_phpDocumentor_setting;
  590.         if (phpDocumentor_setup::checkIgnoreTag($tag->keyword)) return;
  591.         $value = $tag->value;
  592.         if (is_array($value)) $value = $value[0];
  593.         if ($tag->keyword == 'uses')
  594.         {
  595.             $this->addUses($value, $tag->_description);
  596.         } else
  597.         {
  598.             $this->addKeyword($tag->keyword, $value);
  599.         }
  600.     }
  601.  
  602.     /**
  603.      * @param string $keyword tag name
  604.      * @param parserStringWithInlineTags $value the contents of the tag
  605.      * @global array used to determine whether to add the @internal tag or not
  606.      */
  607.     function addKeyword($keyword, $value)
  608.     {
  609.         global $_phpDocumentor_setting;
  610.         $keyword = trim($keyword);
  611.         if (phpDocumentor_setup::checkIgnoreTag($keyword)) return;
  612.         // don't add the tag at all if it was specified to ignore it with --ignore-tags
  613.         if ($keyword == 'package' || $keyword == 'subpackage' || $keyword == 'category') return $this->addPackage($keyword, $value);
  614.         if ($keyword == 'access') return $this->addAccess($value);
  615.         if ($keyword == 'link') return $this->addLink($value);
  616.         if ($keyword == 'see' || $keyword == 'tutorial') return $this->addSee($keyword,$value);
  617.         if ($keyword == 'uses') return $this->addUses($keyword, $value);
  618.         if ($keyword == 'name') return $this->addName($value);
  619.         if (!in_array($keyword,$GLOBALS['_phpDocumentor_tags_allowed']))
  620.         $this->addUnknownTag($keyword,$value);
  621.         else
  622.         {
  623.         if ($keyword == 'internal' && (!isset($_phpDocumentor_setting['parseprivate']) || $_phpDocumentor_setting['parseprivate'] == 'off')) return;
  624.             if (!isset($this->tags[$keyword])) {
  625.                 $this->tags[$keyword] = array();
  626.             }
  627.             $ptag = 'parserTag';
  628.             if (class_exists('parser'.$keyword.'tag'))
  629.                 $ptag = 'parser'.ucfirst($keyword).'Tag';
  630.             array_unshift($this->tags[$keyword], new $ptag($keyword, $value));
  631.         }
  632.     }
  633.     
  634.     /**
  635.      * adds an @example tag
  636.      * @param string contents of the tag
  637.      * @param string path to the file containing this tag
  638.      */
  639.     function addExample($value, $path)
  640.     {
  641.         $this->tags['example'][] = new parserExampleTag($value, $path);
  642.     }
  643.     
  644.     /**
  645.      * adds an unknown tag to the {@link $unknown_tags} array for use by custom converters
  646.      * @param string tag name
  647.      * @param string tag value
  648.      */
  649.     function addUnknownTag($keyword, $value)
  650.     {
  651.         addWarning(PDERROR_UNKNOWN_TAG,$keyword);
  652.         $this->unknown_tags[$keyword][] = new parserTag($keyword, $value);
  653.     }
  654.     
  655.     /**
  656.      * set the element's package to the passed values.  Used in {@link phpDocumentor_IntermediateParser} to align package of
  657.      * elements inside a class or procedural page to the package of the class/procedural page
  658.      * @param string
  659.      * @param string
  660.      * @param string
  661.      * @param string element name
  662.      * @param string element type (include, define, var, method, global, function, const)
  663.      */
  664.     function overridePackage($category, $package,$subpackage,$elname,$type)
  665.     {
  666.         if ($this->package != $GLOBALS['phpDocumentor_DefaultPackageName'])
  667.         {
  668.             addError(PDERROR_OVERRIDDEN_PACKAGE_TAGS,$elname,$type,$this->package);
  669.             $this->explicitpackage = false;
  670.         }
  671.         if (!empty($this->subpackage))
  672.         addError(PDERROR_OVERRIDDEN_SUBPACKAGE_TAGS,$type,$elname,$this->subpackage);
  673.         $this->package = $GLOBALS['phpDocumentor_DefaultPackageName'];
  674.         $this->subpackage = '';
  675.         $this->category = $category;
  676.         $this->addPackage('package',$package);
  677.         $this->addPackage('subpackage',$subpackage);
  678.     }
  679.     
  680.     /**
  681.      * Used if this docblock has a @package tag.
  682.      *
  683.      * phpDocumentor will guess package for DocBlocks that don't have
  684.      * a @package tag
  685.      * @uses $explicitpackage
  686.      */
  687.     function setExplicitPackage()
  688.     {
  689.         $this->explicitpackage = true;
  690.     }
  691.     
  692.     /**
  693.      * If the DocBlock has a @package tag, then this returns true
  694.      * @return boolean
  695.      */
  696.     function getExplicitPackage()
  697.     {
  698.         return $this->explicitpackage;
  699.     }
  700.     
  701.     /**
  702.      * Used if this docblock has a @category tag.
  703.      *
  704.      * phpDocumentor will guess category for DocBlocks that don't have
  705.      * a @category tag
  706.      * @uses $explicitcategory
  707.      */
  708.     function setExplicitCategory()
  709.     {
  710.         $this->explicitcategory = true;
  711.     }
  712.     
  713.     /**
  714.      * If the DocBlock has a @category tag, then this returns true
  715.      * @return boolean
  716.      */
  717.     function getExplicitCategory()
  718.     {
  719.         return $this->explicitcategory;
  720.     }
  721.     
  722.     /**
  723.      * @param string $keyword tag name (either package or subpackage)
  724.      * @param mixed $value either a string or a parserStringWithInlineTags.  Strips all inline tags and use the text as the package
  725.      */
  726.     function addPackage($keyword, $value)
  727.     {
  728.         if ($keyword == 'package')
  729.         {
  730.             if (!$this->explicitpackage)
  731.             {
  732.                 if (!is_string($value))
  733.                 $value = $value->getString();
  734.                 $rest = '';
  735.                 $value = explode(' ',$value);
  736.                 if (count($value) - 1)
  737.                 {
  738.                     $rest = $value;
  739.                     $value = trim($value[0]);
  740.                     unset($rest[0]);
  741.                     $rest = implode($rest,' ');
  742.                 } else
  743.                 {
  744.                     $value = explode("\t",$value[0]);
  745.                     if (count($value) - 1)
  746.                     {
  747.                         $rest = $value;
  748.                         $value = trim($value[0]);
  749.                         unset($rest[0]);
  750.                         $rest = implode($rest,"\t");
  751.                     } else $value = trim($value[0]);
  752.                 }
  753.                 $value = preg_replace('/[^\[\]0-9\-a-zA-Z_\x7f-\xff]/', '-', $value);
  754.                 $this->packagedescrip = $this->package = trim($value);
  755.                 if (!empty($rest)) $this->packagedescrip = $rest;
  756.             } else
  757.             {
  758.                 if (is_string($value))
  759.                 addError(PDERROR_MULTIPLE_PACKAGE_TAGS,$value);
  760.                 else
  761.                 addError(PDERROR_MULTIPLE_PACKAGE_TAGS,$value->getString());
  762.             }
  763.         } elseif ($keyword == 'subpackage')
  764.         {
  765.             if (empty($this->subpackage))
  766.             {
  767.                 if (!is_string($value))
  768.                 $value = $value->getString();
  769.                 $rest = '';
  770.                 $value = explode(' ',$value);
  771.                 if (count($value) - 1)
  772.                 {
  773.                     $rest = $value;
  774.                     $value = $value[0];
  775.                     unset($rest[0]);
  776.                     $rest = implode($rest,' ');
  777.                 } else
  778.                 {
  779.                     $value = explode("\t",$value[0]);
  780.                     if (count($value) - 1)
  781.                     {
  782.                         $rest = $value;
  783.                         $value = $value[0];
  784.                         unset($rest[0]);
  785.                         $rest = implode($rest,"\t");
  786.                     } else $value = $value[0];
  787.                 }
  788.                 if (!empty($value))
  789.                 {
  790.                     $value = preg_replace('/[^\[\]0-9\-a-zA-Z_\x7f-\xff]/', '-', $value);
  791.                 }
  792.                 $this->subpackage = trim($value);
  793.                 if (!empty($rest)) $this->subpackagedescrip = $rest;
  794.             } else
  795.             {
  796.                 if (is_string($value))
  797.                 addError(PDERROR_MULTIPLE_SUBPACKAGE_TAGS,$value);
  798.                 else
  799.                 addError(PDERROR_MULTIPLE_SUBPACKAGE_TAGS,$value->getString());
  800.             }
  801.         } elseif ($keyword == 'category')
  802.         {
  803.             if (!$this->explicitcategory)
  804.             {
  805.                 if (!is_string($value))
  806.                 $value = $value->getString();
  807.                 $value = preg_replace('/[^\[\]0-9\-a-zA-Z_\x7f-\xff]/', '-', $value);
  808.                 $this->category = $value;
  809.             } else
  810.             {
  811.                 if (is_string($value))
  812.                 addError(PDERROR_MULTIPLE_CATEGORY_TAGS,$value);
  813.                 else
  814.                 addError(PDERROR_MULTIPLE_CATEGORY_TAGS,$value->getString());
  815.             }
  816.         }
  817.     }
  818.     
  819.     /**
  820.      * Adds a @name tag to the tag list
  821.      * @param string new name of element
  822.      */
  823.     function addName($value)
  824.     {
  825.         if (is_object($value)) $value = $value->getString();
  826.         if (!$this->hasname)
  827.         {
  828.             $x = new parserNameTag('name',$value);
  829.             $this->hasname = true;
  830.             $this->tags['name'][] = $x;
  831.         } else
  832.         {
  833.             addError(PDERROR_MULTIPLE_NAME_TAGS,$value);
  834.         }
  835.     }
  836.     
  837.     /**
  838.      * @param string if empty, staticvar is indexed in the order received and set using {@link changeStatic()}
  839.      * @param string data type
  840.      * @param parserStringWithInlineTags
  841.      */
  842.     function addStaticVar($staticvar, $type, $descrip)
  843.     {
  844.         if (empty($staticvar))
  845.         $this->statics[] = new parserStaticvarTag($type,$descrip);
  846.         else
  847.         $this->statics[$staticvar] = new parserStaticvarTag($type,$descrip);
  848.     }
  849.     
  850.     /**
  851.      * adds a function declaration of @global to the {@link $funcglobals} array
  852.      * @param string global type
  853.      * @param string description of how the global is used in the function
  854.      */
  855.     function addFuncGlobal($type,$value)
  856.     {
  857.         $this->funcglobals[] = array($type,$value);
  858.     }
  859.     
  860.     /**
  861.      * @param integer $index index of parameter in the {@link $funcglobals} array
  862.      * @param string $name name of the parameter to set in the $funcglobals array
  863.      */
  864.     function changeGlobal($index,$name)
  865.     {
  866.         $this->funcglobals[$name] = $this->funcglobals[$index];
  867.         unset($this->funcglobals[$index]);
  868.     }
  869.  
  870.     /**
  871.      * @param integer $index index of parameter in the {@link $statics} array
  872.      * @param string $name name of the parameter to set in the $statics array
  873.      */
  874.     function changeStatic($index,$name)
  875.     {
  876.         $this->statics[$name] = $this->statics[$index];
  877.         unset($this->statics[$index]);
  878.     }
  879.  
  880.     /**
  881.      * replaces nameless global variables in the {@link $funcglobals} array with their names
  882.      * @param array
  883.      */
  884.     function updateGlobals($funcs)
  885.     {
  886.         for($i=0;$i<count($funcs);$i++)
  887.         {
  888.             if (isset($this->funcglobals[$i]))
  889.             {
  890.                 $this->changeGlobal($i,$funcs[$i]);
  891.             }
  892.         }
  893.     }
  894.  
  895.     /**
  896.      * replaces nameless static variables in the {@link $statics} array with their names
  897.      * @param array
  898.      */
  899.     function updateStatics($funcs)
  900.     {
  901.         for($i=0;$i<count($funcs);$i++)
  902.         {
  903.             if (isset($this->statics[$i]))
  904.             {
  905.                 $this->changeStatic($i,$funcs[$i]);
  906.             }
  907.         }
  908.     }
  909.  
  910.     /**
  911.      * add an @access tag to the {@link tags} array
  912.      * @param string should be either public or private
  913.      */
  914.     function addAccess($value)
  915.     {
  916.         if (is_object($value)) $value = $value->getString();
  917.         $value = strtolower($value);
  918.         if (!$this->hasaccess)
  919.         {
  920.             $x = new parserAccessTag($value);
  921.             if ($x->isvalid)
  922.             {
  923.                 $this->hasaccess = true;
  924.                 $this->tags['access'][] = $x;
  925.             }
  926.         } else
  927.         {
  928.             if (is_string($value))
  929.             addError(PDERROR_MULTIPLE_ACCESS_TAGS,$value);
  930.             else
  931.             addError(PDERROR_MULTIPLE_ACCESS_TAGS,$value->getString());
  932.         }
  933.     }
  934.     
  935.     /**
  936.      * Adds a new @filesource tag to the DocBlock
  937.      * @tutorial tags.filesource.pkg
  938.      * @param string full path to the file
  939.      * @param array tokenized source code, ordered by line number
  940.      */
  941.     function addFileSource($path, $source)
  942.     {
  943.         if (isset($this->tags['filesource'])) return;
  944.         $this->tags['filesource'][] = new parserFileSourceTag($path, $source);
  945.     }
  946.     
  947.     /**
  948.      * creates a {@link parserLinkTag} and adds it to the {@link $tags} array
  949.      * @param string $link
  950.      */
  951.     function addLink($link)
  952.     {
  953.         if (phpDocumentor_setup::checkIgnoreTag('@link')) return;
  954.         $this->tags['link'][] = new parserLinkTag($link);
  955.     }
  956.     
  957.     /**
  958.      * creates a {@link parserLinkTag} and adds it to the {@link $tags} array
  959.      * @param string either see or uses
  960.      * @param string $value
  961.      */
  962.     function addSee($keyword,$value)
  963.     {
  964.         if (phpDocumentor_setup::checkIgnoreTag($keyword)) return;
  965.         $tag = 'parser'.ucfirst($keyword).'Tag';
  966.         $this->tags[$keyword][] = new $tag($value);
  967.     }
  968.     
  969.     /**
  970.      * creates a {@link parserReturnTag} and adds it to the {@link $tags} array
  971.      * @param string $returnType the one-word name of the return type (mixed should be used if more than one type)
  972.      * @param parserStringWithInlineTags $value
  973.      */
  974.     function addReturn($returnType, $value)
  975.     {
  976.         // only take the first one
  977.         if (!$this->return)
  978.         {
  979.             $this->return = new parserReturnTag($returnType, $value);
  980.         } else
  981.         {
  982.             addError(PDERROR_MULTIPLE_RETURN_TAGS,$returnType,$value->getString());
  983.         }
  984.     }
  985.     
  986.     /**
  987.      * creates a {@link parserVarTag} and adds it to the {@link $tags} array
  988.      * @param string $varType the one-word name of the variable type (mixed should be used if more than one type)
  989.      * @param parserStringWithInlineTags $value
  990.      */
  991.     function addVar($varType, $value)
  992.     {
  993.         // only take the first one
  994.         if (!$this->var)
  995.         {
  996.             $this->var = new parserVarTag($varType, $value);
  997.         } else
  998.         {
  999.             addError(PDERROR_MULTIPLE_VAR_TAGS,$varType,$value->getString());
  1000.         }
  1001.     }
  1002.     
  1003.     /**
  1004.      * Adds a virtual @usedby tag to output
  1005.      * @param abstractLink link to the element that has a @uses tag
  1006.      * @param parserStringWithInlinetags description of how the elements uses
  1007.      *                                   this one
  1008.      * @access private
  1009.      */
  1010.     function addUsedBy($link, $descrip)
  1011.     {
  1012.         $this->tags['usedby'][] = new parserUsedByTag($link, $descrip);
  1013.     }
  1014.     
  1015.     /**
  1016.      * Add a @uses tag to the DocBlock
  1017.      * @param string @see-style text, used for {@link Converter::getLink()}
  1018.      * @param parserStringWithInlineTags description of how the used element is
  1019.      *                                   used
  1020.      * @tutorial tags.uses.pkg
  1021.      */
  1022.     function addUses($seeel, $description)
  1023.     {
  1024.         $this->tags['uses'][] = new parserUsesTag($seeel, $description);
  1025.         usort($this->tags['uses'], array($this, '_sortUses'));
  1026.     }
  1027.  
  1028.     /**
  1029.      * Adds a @property(-read or -write) or @method magic tag to the DocBlock
  1030.      */
  1031.     function addProperty( $tagName, $propertyName, $propertyType, $value )
  1032.     {
  1033.         if ( empty( $propertyName ) )
  1034.         {
  1035.             addWarning ( PDERROR_MISSING_PROPERTY_TAG_NAME, $tagName, $tagName, $propertyType, $value->getString() );
  1036.         }
  1037.         else
  1038.         {
  1039.             switch ( $tagName )
  1040.             {
  1041.             case 'property':
  1042.                 $this->properties[ $propertyName ] = new parserPropertyTag( $propertyType, $value );
  1043.                 break;
  1044.             case 'property-read':
  1045.                 $this->properties[ $propertyName ] = new parserPropertyReadTag( $propertyType, $value );
  1046.                 break;
  1047.             case 'property-write':
  1048.                 $this->properties[ $propertyName ] = new parserPropertyWriteTag( $propertyType, $value );
  1049.                 break;
  1050.             case 'method':
  1051.                 $this->properties[ $propertyName ] = new parserMethodTag( $propertyType, $value );
  1052.                 break;
  1053.             }
  1054.         }
  1055.     }
  1056.  
  1057.     /**
  1058.      * Custom sorting function for sorting @uses tags
  1059.      *
  1060.      * @param parserTag $a
  1061.      * @param parserTag $b
  1062.      * @access private
  1063.      * @return int
  1064.      */
  1065.     function _sortUses($a, $b)
  1066.     {
  1067.         return strnatcasecmp($a->getString(), $b->getString());
  1068.     }
  1069.  
  1070.     /**
  1071.      * @param string
  1072.      * @return mixed false if no keyword, unconverted value if one keyword, array of unconverted values if more than one keyword
  1073.      */
  1074.     function getKeyword($keyword)
  1075.     {
  1076.         if ($keyword == 'filesource' && !$this->_canSource) return false;
  1077.         if (isset($this->tags[$keyword]))
  1078.         {
  1079.             if (count($this->tags[$keyword]) == 1)
  1080.             {
  1081.                 return $this->tags[$keyword][0];
  1082.             } else return $this->tags[$keyword];
  1083.         } else return false;
  1084.     }
  1085.     
  1086.     /**
  1087.      * @return array Format: array('var' => tag name, 'data' => unconverted tag value)
  1088.      */
  1089.     function listParams()
  1090.     {
  1091.         if (isset($this->params))
  1092.         {
  1093.             $ret = array();
  1094.             foreach($this->params as $key => $val)
  1095.             {
  1096.                 $ret[] = array("var" => ucfirst($key),"data" => $val);
  1097.             }
  1098.             return $ret;
  1099.         } else {
  1100.             return array();
  1101.         }
  1102.     }
  1103.  
  1104.     /**
  1105.      * @return array Format: array('var' => tag name, 'data' => unconverted tag value)
  1106.      */
  1107.     function listProperties()
  1108.     {
  1109.         $ret = array();
  1110.         if (isset($this->properties))
  1111.         {
  1112.             foreach($this->properties as $key => $val)
  1113.             {
  1114.                 $ret[] = array("var" => ucfirst($key),"data" => $val);
  1115.             }
  1116.         }
  1117.         return $ret;
  1118.     }
  1119.     
  1120.     /**
  1121.      * @param Converter
  1122.      */
  1123.     function listTags()
  1124.     {
  1125.         $tags = array();
  1126.         foreach($this->tags as $keyword => $vals)
  1127.         {
  1128.             if ($keyword == 'filesource' && !$this->_canSource) continue;
  1129.             foreach($vals as $val)
  1130.             {
  1131.                 $tags[] = $val;
  1132.             }
  1133.         }
  1134.         usort($tags,'tagsort');
  1135.         return $tags;
  1136.     }
  1137.     
  1138.     /** @return string always 'docblock' */
  1139.     function getType()
  1140.     {
  1141.         return 'docblock';
  1142.     }
  1143. }
  1144.  
  1145. /**
  1146.  * Determines the arbitrary tag rank value for a given tag
  1147.  * @access private
  1148.  */
  1149. function getTagRanking($tag)
  1150. {
  1151.     switch(phpDocumentor_get_class($tag))
  1152.     {
  1153.         case 'parserreturntag' :
  1154.             $o = 0;
  1155.             break;
  1156.         case 'parservartag' :
  1157.             $o = 1;
  1158.             break;
  1159.         case 'parsertutorialtag' :
  1160.             $o = 2;
  1161.             break;
  1162.         case 'parserstaticvartag' :
  1163.             $o = 3;
  1164.             break;
  1165.         case 'parserseetag' :
  1166.             $o = 10;
  1167.             break;
  1168.         case 'parserlinktag' :
  1169.             $o = 11;
  1170.             break;
  1171.         case 'parsertag' :
  1172.             switch ($tag->keyword)
  1173.             {
  1174.                 case 'author' :
  1175.                     $o = 4;
  1176.                     break;
  1177.                 case 'version' :
  1178.                     $o = 5;
  1179.                     break;
  1180.                 case 'copyright' :
  1181.                     $o = 6;
  1182.                     break;
  1183.                 case 'deprecated' :
  1184.                 case 'deprec' :
  1185.                     $o = 12;
  1186.                     break;
  1187.                 case 'todo' :
  1188.                 case 'TODO' :
  1189.                     $o = 13;
  1190.                     break;
  1191.                 case 'abstract' :
  1192.                     $o = 14;
  1193.                     break;
  1194.                 default :
  1195.                     $o = 15;
  1196.                     break;
  1197.             }
  1198.             break;
  1199.         case 'parseraccesstag' :
  1200.             $o = 18;
  1201.             break;
  1202.         case 'parsernametag' :
  1203.             $o = 19;
  1204.             break;
  1205.         default :
  1206.             $o = 20;
  1207.             break;
  1208.     }
  1209.     return $o;
  1210. }
  1211.  
  1212. /**
  1213.  * Utilizes the getTagRanking method to determine tag sort order of two given tags
  1214.  * @access private
  1215.  */
  1216. function tagsort($a, $b)
  1217. {
  1218.     $returnval = 0;
  1219.     $o = getTagRanking($a);
  1220.     $p = getTagRanking($b);
  1221.     if ($o == $p) return 0;
  1222.     if ($o < $p) return -1;
  1223.     if ($o > $p) return 1;
  1224. }
  1225. ?>
  1226.