Overview

Packages

  • Reflection

Classes

  • Horde_Reflection
  • Horde_Reflection_CLI
  • Horde_Reflection_Html
  • Horde_Reflection_Wiki
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * The Horde_Reflection class provides reflection methods, e.g. to generate
  4:  * method documentation.
  5:  *
  6:  * Based on the PEAR XML_RPC2_Server_Method class by Sergio Carvalho
  7:  *
  8:  * Copyright 2004-2006 Sergio Gonalves Carvalho
  9:  *                     (<sergio.carvalho@portugalmail.com>)
 10:  * Copyright 2008-2012 Horde LLC (http://www.horde.org/)
 11:  *
 12:  * See the enclosed file COPYING for license information (LGPL). If you
 13:  * did not receive this file, see http://www.horde.org/licenses/lgpl21.
 14:  *
 15:  * @author  Sergio Carvalho <sergio.carvalho@portugalmail.com>
 16:  * @author  Duck <duck@obala.net>
 17:  * @author  Jan Schneider <jan@horde.org>
 18:  * @package Reflection
 19:  */
 20: abstract class Horde_Reflection {
 21: 
 22:     /**
 23:      * Method signature parameters.
 24:      *
 25:      * @var array
 26:      */
 27:     protected $_parameters;
 28: 
 29:     /**
 30:      * Method signature return type.
 31:      *
 32:      * @var string
 33:      */
 34:     protected $_returns;
 35: 
 36:     /**
 37:      * Method help, for introspection.
 38:      *
 39:      * @var string
 40:      */
 41:     protected $_help;
 42: 
 43:     /**
 44:      * Number of required parameters.
 45:      *
 46:      * @var integer
 47:      */
 48:     protected $_numberOfRequiredParameters;
 49: 
 50:     /**
 51:      * External method name.
 52:      *
 53:      * @var string
 54:      */
 55:     protected $_name;
 56: 
 57:     /**
 58:      * Constructor.
 59:      *
 60:      * @param ReflectionMethod $method  The PHP method to introspect.
 61:      */
 62:     public function __construct(ReflectionFunction $method)
 63:     {
 64:         $docs = $method->getDocComment();
 65:         $docs = explode("\n", $docs);
 66: 
 67:         $parameters = array();
 68:         $returns = 'mixed';
 69:         $shortdesc = '';
 70:         $paramcount = -1;
 71:         $this->_name = $method->getName();
 72: 
 73:         // Extract info from docblock.
 74:         $paramDocs = array();
 75:         foreach ($docs as $i => $doc) {
 76:             $doc = trim($doc, " \r\t/*");
 77:             if (strlen($doc) && strpos($doc, '@') !== 0) {
 78:                 if ($shortdesc) {
 79:                     $shortdesc .= "\n";
 80:                 }
 81:                 $shortdesc .= $doc;
 82:                 continue;
 83:             }
 84:             if (strpos($doc, '@param') === 0) {
 85:                 // Save doctag for usage later when filling parameters.
 86:                 $paramDocs[] = $doc;
 87:             }
 88: 
 89:             if (strpos($doc, '@return') === 0) {
 90:                 $param = preg_split("/\s+/", $doc);
 91:                 if (isset($param[1])) {
 92:                     $param = $param[1];
 93:                     $returns = $param;
 94:                 }
 95:             }
 96:         }
 97: 
 98:         // We don't use isOptional() because of bugs in the reflection API.
 99:         $this->_numberOfRequiredParameters = $method->getNumberOfRequiredParameters();
100:         // Fill in info for each method parameter.
101:         foreach ($method->getParameters() as $parameterIndex => $parameter) {
102:             // Parameter defaults.
103:             $newParameter = array('type' => 'mixed');
104: 
105:             // Attempt to extract type and doc from docblock.
106:             if (array_key_exists($parameterIndex, $paramDocs) &&
107:                 preg_match('/@param\s+(\S+)(\s+(.+))/',
108:                            $paramDocs[$parameterIndex],
109:                            $matches)) {
110:                 if (strpos($matches[1], '|')) {
111:                     $newParameter['type'] = self::_limitPHPType(explode('|', $matches[1]));
112:                 } else {
113:                     $newParameter['type'] = self::_limitPHPType($matches[1]);
114:                 }
115:                 $tmp = '$' . $parameter->getName() . ' ';
116:                 if (strpos($matches[2], '$' . $tmp) === 0) {
117:                     $newParameter['doc'] = $matches[2];
118:                 } else {
119:                     // The phpdoc comment is something like "@param string
120:                     // $param description of param". Let's keep only
121:                     // "description of param" as documentation (remove
122:                     // $param).
123:                     $newParameter['doc'] = substr($matches[2], strlen($tmp));
124:                 }
125:             }
126: 
127:             $parameters[$parameter->getName()] = $newParameter;
128:         }
129: 
130:         $this->_parameters = $parameters;
131:         $this->_returns  = $returns;
132:         $this->_help = $shortdesc;
133:     }
134: 
135:     /**
136:      * Returns a complete description of the method.
137:      *
138:      * @return string  The method documentation.
139:      */
140:     abstract public function autoDocument();
141: 
142:     /**
143:      * Converts types from phpdoc comments (and limit to xmlrpc available
144:      * types) to php type names.
145:      *
146:      * @var string|array $type  One or multiple phpdoc comment type(s).
147:      *
148:      * @return string|array  The standardized php type(s).
149:      */
150:     protected static function _limitPHPType($type)
151:     {
152:         $convertArray = array(
153:                 'int' => 'integer',
154:                 'i4' => 'integer',
155:                 'integer' => 'integer',
156:                 'string' => 'string',
157:                 'str' => 'string',
158:                 'char' => 'string',
159:                 'bool' => 'boolean',
160:                 'boolean' => 'boolean',
161:                 'array' => 'array',
162:                 'float' => 'double',
163:                 'double' => 'double',
164:                 'array' => 'array',
165:                 'struct' => 'array',
166:                 'assoc' => 'array',
167:                 'structure' => 'array',
168:                 'datetime' => 'mixed',
169:                 'datetime.iso8601' => 'mixed',
170:                 'iso8601' => 'mixed',
171:                 'base64' => 'string'
172:             );
173: 
174: 
175:         if (is_array($type)) {
176:             $types = array();
177:             foreach ($type as $tmp) {
178:                 $tmp = Horde_String::lower($tmp);
179:                 if (isset($convertArray[$tmp])) {
180:                     $types[] = $convertArray[$tmp];
181:                 } else {
182:                     $types[] = 'mixes';
183:                 }
184:             }
185:             return $types;
186:         } else {
187:             $tmp = Horde_String::lower($type);
188:             if (isset($convertArray[$tmp])) {
189:                 return $convertArray[$tmp];
190:             }
191:         }
192: 
193:         return 'mixed';
194:     }
195: 
196:     /**
197:      * Attempts to return a concrete Horde_Document instance based on $driver.
198:      *
199:      * @param string $function  The method to document.
200:      * @param string $driver    The type of the concrete Horde_Document
201:      *                          subclass to return. The class name is based on
202:      *                          the driver.  The code is dynamically included.
203:      *
204:      * @return Horde_Document  The newly created concrete Horde_Document
205:      *                         instance, or false on an error.
206:      */
207:     public static function factory($function, $driver = 'Html')
208:     {
209:         $class = 'Horde_Reflection_' . $driver;
210:         if (!class_exists($class)) {
211:             include dirname(__FILE__) . '/Reflection/' . $driver . '.php';
212:         }
213:         if (class_exists($class)) {
214:             return new $class($function);
215:         } else {
216:             return false;
217:         }
218:     }
219: 
220: }
221: 
API documentation generated by ApiGen