[ Index ] |
PHP Cross Reference of moodle-2.8 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Zend Framework 4 * 5 * LICENSE 6 * 7 * This source file is subject to the new BSD license that is bundled 8 * with this package in the file LICENSE.txt. 9 * It is also available through the world-wide-web at this URL: 10 * http://framework.zend.com/license/new-bsd 11 * If you did not receive a copy of the license and are unable to 12 * obtain it through the world-wide-web, please send an email 13 * to [email protected] so we can send you a copy immediately. 14 * 15 * @category Zend 16 * @package Zend_Server 17 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) 18 * @license http://framework.zend.com/license/new-bsd New BSD License 19 */ 20 21 /** 22 * Zend_Server_Reflection_Node 23 */ 24 require_once 'Zend/Server/Reflection/Node.php'; 25 26 /** 27 * Zend_Server_Reflection_Parameter 28 */ 29 require_once 'Zend/Server/Reflection/Parameter.php'; 30 31 /** 32 * Zend_Server_Reflection_Prototype 33 */ 34 require_once 'Zend/Server/Reflection/Prototype.php'; 35 36 /** 37 * Function/Method Reflection 38 * 39 * Decorates a ReflectionFunction. Allows setting and retrieving an alternate 40 * 'service' name (i.e., the name to be used when calling via a service), 41 * setting and retrieving the description (originally set using the docblock 42 * contents), retrieving the callback and callback type, retrieving additional 43 * method invocation arguments, and retrieving the 44 * method {@link Zend_Server_Reflection_Prototype prototypes}. 45 * 46 * @category Zend 47 * @package Zend_Server 48 * @subpackage Reflection 49 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) 50 * @license http://framework.zend.com/license/new-bsd New BSD License 51 * @version $Id$ 52 */ 53 abstract class Zend_Server_Reflection_Function_Abstract 54 { 55 /** 56 * @var ReflectionFunction 57 */ 58 protected $_reflection; 59 60 /** 61 * Additional arguments to pass to method on invocation 62 * @var array 63 */ 64 protected $_argv = array(); 65 66 /** 67 * Used to store extra configuration for the method (typically done by the 68 * server class, e.g., to indicate whether or not to instantiate a class). 69 * Associative array; access is as properties via {@link __get()} and 70 * {@link __set()} 71 * @var array 72 */ 73 protected $_config = array(); 74 75 /** 76 * Declaring class (needed for when serialization occurs) 77 * @var string 78 */ 79 protected $_class; 80 81 /** 82 * Function/method description 83 * @var string 84 */ 85 protected $_description = ''; 86 87 /** 88 * Namespace with which to prefix function/method name 89 * @var string 90 */ 91 protected $_namespace; 92 93 /** 94 * Prototypes 95 * @var array 96 */ 97 protected $_prototypes = array(); 98 99 private $_return; 100 private $_returnDesc; 101 private $_paramDesc; 102 private $_sigParams; 103 private $_sigParamsDepth; 104 105 /** 106 * Constructor 107 * 108 * @param ReflectionFunction $r 109 */ 110 public function __construct(Reflector $r, $namespace = null, $argv = array()) 111 { 112 // In PHP 5.1.x, ReflectionMethod extends ReflectionFunction. In 5.2.x, 113 // both extend ReflectionFunctionAbstract. So, we can't do normal type 114 // hinting in the prototype, but instead need to do some explicit 115 // testing here. 116 if ((!$r instanceof ReflectionFunction) 117 && (!$r instanceof ReflectionMethod)) { 118 require_once 'Zend/Server/Reflection/Exception.php'; 119 throw new Zend_Server_Reflection_Exception('Invalid reflection class'); 120 } 121 $this->_reflection = $r; 122 123 // Determine namespace 124 if (null !== $namespace){ 125 $this->setNamespace($namespace); 126 } 127 128 // Determine arguments 129 if (is_array($argv)) { 130 $this->_argv = $argv; 131 } 132 133 // If method call, need to store some info on the class 134 if ($r instanceof ReflectionMethod) { 135 $this->_class = $r->getDeclaringClass()->getName(); 136 } 137 138 // Perform some introspection 139 $this->_reflect(); 140 } 141 142 /** 143 * Create signature node tree 144 * 145 * Recursive method to build the signature node tree. Increments through 146 * each array in {@link $_sigParams}, adding every value of the next level 147 * to the current value (unless the current value is null). 148 * 149 * @param Zend_Server_Reflection_Node $parent 150 * @param int $level 151 * @return void 152 */ 153 protected function _addTree(Zend_Server_Reflection_Node $parent, $level = 0) 154 { 155 if ($level >= $this->_sigParamsDepth) { 156 return; 157 } 158 159 foreach ($this->_sigParams[$level] as $value) { 160 $node = new Zend_Server_Reflection_Node($value, $parent); 161 if ((null !== $value) && ($this->_sigParamsDepth > $level + 1)) { 162 $this->_addTree($node, $level + 1); 163 } 164 } 165 } 166 167 /** 168 * Build the signature tree 169 * 170 * Builds a signature tree starting at the return values and descending 171 * through each method argument. Returns an array of 172 * {@link Zend_Server_Reflection_Node}s. 173 * 174 * @return array 175 */ 176 protected function _buildTree() 177 { 178 $returnTree = array(); 179 foreach ((array) $this->_return as $value) { 180 $node = new Zend_Server_Reflection_Node($value); 181 $this->_addTree($node); 182 $returnTree[] = $node; 183 } 184 185 return $returnTree; 186 } 187 188 /** 189 * Build method signatures 190 * 191 * Builds method signatures using the array of return types and the array of 192 * parameters types 193 * 194 * @param array $return Array of return types 195 * @param string $returnDesc Return value description 196 * @param array $params Array of arguments (each an array of types) 197 * @param array $paramDesc Array of parameter descriptions 198 * @return array 199 */ 200 protected function _buildSignatures($return, $returnDesc, $paramTypes, $paramDesc) 201 { 202 $this->_return = $return; 203 $this->_returnDesc = $returnDesc; 204 $this->_paramDesc = $paramDesc; 205 $this->_sigParams = $paramTypes; 206 $this->_sigParamsDepth = count($paramTypes); 207 $signatureTrees = $this->_buildTree(); 208 $signatures = array(); 209 210 $endPoints = array(); 211 foreach ($signatureTrees as $root) { 212 $tmp = $root->getEndPoints(); 213 if (empty($tmp)) { 214 $endPoints = array_merge($endPoints, array($root)); 215 } else { 216 $endPoints = array_merge($endPoints, $tmp); 217 } 218 } 219 220 foreach ($endPoints as $node) { 221 if (!$node instanceof Zend_Server_Reflection_Node) { 222 continue; 223 } 224 225 $signature = array(); 226 do { 227 array_unshift($signature, $node->getValue()); 228 $node = $node->getParent(); 229 } while ($node instanceof Zend_Server_Reflection_Node); 230 231 $signatures[] = $signature; 232 } 233 234 // Build prototypes 235 $params = $this->_reflection->getParameters(); 236 foreach ($signatures as $signature) { 237 $return = new Zend_Server_Reflection_ReturnValue(array_shift($signature), $this->_returnDesc); 238 $tmp = array(); 239 foreach ($signature as $key => $type) { 240 $param = new Zend_Server_Reflection_Parameter($params[$key], $type, (isset($this->_paramDesc[$key]) ? $this->_paramDesc[$key] : null)); 241 $param->setPosition($key); 242 $tmp[] = $param; 243 } 244 245 $this->_prototypes[] = new Zend_Server_Reflection_Prototype($return, $tmp); 246 } 247 } 248 249 /** 250 * Use code reflection to create method signatures 251 * 252 * Determines the method help/description text from the function DocBlock 253 * comment. Determines method signatures using a combination of 254 * ReflectionFunction and parsing of DocBlock @param and @return values. 255 * 256 * @param ReflectionFunction $function 257 * @return array 258 */ 259 protected function _reflect() 260 { 261 $function = $this->_reflection; 262 $helpText = ''; 263 $signatures = array(); 264 $returnDesc = ''; 265 $paramCount = $function->getNumberOfParameters(); 266 $paramCountRequired = $function->getNumberOfRequiredParameters(); 267 $parameters = $function->getParameters(); 268 $docBlock = $function->getDocComment(); 269 270 if (!empty($docBlock)) { 271 // Get help text 272 if (preg_match(':/\*\*\s*\r?\n\s*\*\s(.*?)\r?\n\s*\*(\s@|/):s', $docBlock, $matches)) 273 { 274 $helpText = $matches[1]; 275 $helpText = preg_replace('/(^\s*\*\s)/m', '', $helpText); 276 $helpText = preg_replace('/\r?\n\s*\*\s*(\r?\n)*/s', "\n", $helpText); 277 $helpText = trim($helpText); 278 } 279 280 // Get return type(s) and description 281 $return = 'void'; 282 if (preg_match('/@return\s+(\S+)/', $docBlock, $matches)) { 283 $return = explode('|', $matches[1]); 284 if (preg_match('/@return\s+\S+\s+(.*?)(@|\*\/)/s', $docBlock, $matches)) 285 { 286 $value = $matches[1]; 287 $value = preg_replace('/\s?\*\s/m', '', $value); 288 $value = preg_replace('/\s{2,}/', ' ', $value); 289 $returnDesc = trim($value); 290 } 291 } 292 293 // Get param types and description 294 if (preg_match_all('/@param\s+([^\s]+)/m', $docBlock, $matches)) { 295 $paramTypesTmp = $matches[1]; 296 if (preg_match_all('/@param\s+\S+\s+(\$\S+)\s+(.*?)(@|\*\/)/s', $docBlock, $matches)) 297 { 298 $paramDesc = $matches[2]; 299 foreach ($paramDesc as $key => $value) { 300 $value = preg_replace('/\s?\*\s/m', '', $value); 301 $value = preg_replace('/\s{2,}/', ' ', $value); 302 $paramDesc[$key] = trim($value); 303 } 304 } 305 } 306 } else { 307 $helpText = $function->getName(); 308 $return = 'void'; 309 } 310 311 // Set method description 312 $this->setDescription($helpText); 313 314 // Get all param types as arrays 315 if (!isset($paramTypesTmp) && (0 < $paramCount)) { 316 $paramTypesTmp = array_fill(0, $paramCount, 'mixed'); 317 } elseif (!isset($paramTypesTmp)) { 318 $paramTypesTmp = array(); 319 } elseif (count($paramTypesTmp) < $paramCount) { 320 $start = $paramCount - count($paramTypesTmp); 321 for ($i = $start; $i < $paramCount; ++$i) { 322 $paramTypesTmp[$i] = 'mixed'; 323 } 324 } 325 326 // Get all param descriptions as arrays 327 if (!isset($paramDesc) && (0 < $paramCount)) { 328 $paramDesc = array_fill(0, $paramCount, ''); 329 } elseif (!isset($paramDesc)) { 330 $paramDesc = array(); 331 } elseif (count($paramDesc) < $paramCount) { 332 $start = $paramCount - count($paramDesc); 333 for ($i = $start; $i < $paramCount; ++$i) { 334 $paramDesc[$i] = ''; 335 } 336 } 337 338 if (count($paramTypesTmp) != $paramCount) { 339 require_once 'Zend/Server/Reflection/Exception.php'; 340 throw new Zend_Server_Reflection_Exception( 341 'Variable number of arguments is not supported for services (except optional parameters). ' 342 . 'Number of function arguments must correspond to actual number of arguments described in a docblock ' 343 . '(function was ' . $function->getName() . ')'); 344 } 345 346 $paramTypes = array(); 347 foreach ($paramTypesTmp as $i => $param) { 348 $tmp = explode('|', $param); 349 if ($parameters[$i]->isOptional()) { 350 array_unshift($tmp, null); 351 } 352 $paramTypes[] = $tmp; 353 } 354 355 $this->_buildSignatures($return, $returnDesc, $paramTypes, $paramDesc); 356 } 357 358 359 /** 360 * Proxy reflection calls 361 * 362 * @param string $method 363 * @param array $args 364 * @return mixed 365 */ 366 public function __call($method, $args) 367 { 368 if (method_exists($this->_reflection, $method)) { 369 return call_user_func_array(array($this->_reflection, $method), $args); 370 } 371 372 require_once 'Zend/Server/Reflection/Exception.php'; 373 throw new Zend_Server_Reflection_Exception('Invalid reflection method ("' .$method. '")'); 374 } 375 376 /** 377 * Retrieve configuration parameters 378 * 379 * Values are retrieved by key from {@link $_config}. Returns null if no 380 * value found. 381 * 382 * @param string $key 383 * @return mixed 384 */ 385 public function __get($key) 386 { 387 if (isset($this->_config[$key])) { 388 return $this->_config[$key]; 389 } 390 391 return null; 392 } 393 394 /** 395 * Set configuration parameters 396 * 397 * Values are stored by $key in {@link $_config}. 398 * 399 * @param string $key 400 * @param mixed $value 401 * @return void 402 */ 403 public function __set($key, $value) 404 { 405 $this->_config[$key] = $value; 406 } 407 408 /** 409 * Set method's namespace 410 * 411 * @param string $namespace 412 * @return void 413 */ 414 public function setNamespace($namespace) 415 { 416 if (empty($namespace)) { 417 $this->_namespace = ''; 418 return; 419 } 420 421 if (!is_string($namespace) || !preg_match('/[a-z0-9_\.]+/i', $namespace)) { 422 require_once 'Zend/Server/Reflection/Exception.php'; 423 throw new Zend_Server_Reflection_Exception('Invalid namespace'); 424 } 425 426 $this->_namespace = $namespace; 427 } 428 429 /** 430 * Return method's namespace 431 * 432 * @return string 433 */ 434 public function getNamespace() 435 { 436 return $this->_namespace; 437 } 438 439 /** 440 * Set the description 441 * 442 * @param string $string 443 * @return void 444 */ 445 public function setDescription($string) 446 { 447 if (!is_string($string)) { 448 require_once 'Zend/Server/Reflection/Exception.php'; 449 throw new Zend_Server_Reflection_Exception('Invalid description'); 450 } 451 452 $this->_description = $string; 453 } 454 455 /** 456 * Retrieve the description 457 * 458 * @return void 459 */ 460 public function getDescription() 461 { 462 return $this->_description; 463 } 464 465 /** 466 * Retrieve all prototypes as array of 467 * {@link Zend_Server_Reflection_Prototype Zend_Server_Reflection_Prototypes} 468 * 469 * @return array 470 */ 471 public function getPrototypes() 472 { 473 return $this->_prototypes; 474 } 475 476 /** 477 * Retrieve additional invocation arguments 478 * 479 * @return array 480 */ 481 public function getInvokeArguments() 482 { 483 return $this->_argv; 484 } 485 486 /** 487 * Wakeup from serialization 488 * 489 * Reflection needs explicit instantiation to work correctly. Re-instantiate 490 * reflection object on wakeup. 491 * 492 * @return void 493 */ 494 public function __wakeup() 495 { 496 if ($this->_reflection instanceof ReflectionMethod) { 497 $class = new ReflectionClass($this->_class); 498 $this->_reflection = new ReflectionMethod($class->newInstance(), $this->getName()); 499 } else { 500 $this->_reflection = new ReflectionFunction($this->getName()); 501 } 502 } 503 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:29:05 2014 | Cross-referenced by PHPXref 0.7.1 |