Viewing file: Abstract.php (15.14 KB) -rw-rw-rw- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php /** * Zend Framework * * LICENSE * * This source file is subject to the new BSD license that is bundled * with this package in the file LICENSE.txt. * It is also available through the world-wide-web at this URL: * http://framework.zend.com/license/new-bsd * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to license@zend.com so we can send you a copy immediately. * * @category Zend * @package Zend_Server * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */
/** * Zend_Server_Reflection_Node */ require_once 'Zend/Server/Reflection/Node.php';
/** * Zend_Server_Reflection_Parameter */ require_once 'Zend/Server/Reflection/Parameter.php';
/** * Zend_Server_Reflection_Prototype */ require_once 'Zend/Server/Reflection/Prototype.php';
/** * Function/Method Reflection * * Decorates a ReflectionFunction. Allows setting and retrieving an alternate * 'service' name (i.e., the name to be used when calling via a service), * setting and retrieving the description (originally set using the docblock * contents), retrieving the callback and callback type, retrieving additional * method invocation arguments, and retrieving the * method {@link Zend_Server_Reflection_Prototype prototypes}. * * @category Zend * @package Zend_Server * @subpackage Reflection * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License * @version $Id: Abstract.php 16210 2009-06-21 19:22:17Z thomas $ */ abstract class Zend_Server_Reflection_Function_Abstract { /** * @var ReflectionFunction */ protected $_reflection;
/** * Additional arguments to pass to method on invocation * @var array */ protected $_argv = array();
/** * Used to store extra configuration for the method (typically done by the * server class, e.g., to indicate whether or not to instantiate a class). * Associative array; access is as properties via {@link __get()} and * {@link __set()} * @var array */ protected $_config = array();
/** * Declaring class (needed for when serialization occurs) * @var string */ protected $_class;
/** * Function/method description * @var string */ protected $_description = '';
/** * Namespace with which to prefix function/method name * @var string */ protected $_namespace;
/** * Prototypes * @var array */ protected $_prototypes = array();
private $_return; private $_returnDesc; private $_paramDesc; private $_sigParams; private $_sigParamsDepth;
/** * Constructor * * @param ReflectionFunction $r */ public function __construct(Reflector $r, $namespace = null, $argv = array()) { // In PHP 5.1.x, ReflectionMethod extends ReflectionFunction. In 5.2.x, // both extend ReflectionFunctionAbstract. So, we can't do normal type // hinting in the prototype, but instead need to do some explicit // testing here. if ((!$r instanceof ReflectionFunction) && (!$r instanceof ReflectionMethod)) { require_once 'Zend/Server/Reflection/Exception.php'; throw new Zend_Server_Reflection_Exception('Invalid reflection class'); } $this->_reflection = $r;
// Determine namespace if (null !== $namespace){ $this->setNamespace($namespace); }
// Determine arguments if (is_array($argv)) { $this->_argv = $argv; }
// If method call, need to store some info on the class if ($r instanceof ReflectionMethod) { $this->_class = $r->getDeclaringClass()->getName(); }
// Perform some introspection $this->_reflect(); }
/** * Create signature node tree * * Recursive method to build the signature node tree. Increments through * each array in {@link $_sigParams}, adding every value of the next level * to the current value (unless the current value is null). * * @param Zend_Server_Reflection_Node $parent * @param int $level * @return void */ protected function _addTree(Zend_Server_Reflection_Node $parent, $level = 0) { if ($level >= $this->_sigParamsDepth) { return; }
foreach ($this->_sigParams[$level] as $value) { $node = new Zend_Server_Reflection_Node($value, $parent); if ((null !== $value) && ($this->_sigParamsDepth > $level + 1)) { $this->_addTree($node, $level + 1); } } }
/** * Build the signature tree * * Builds a signature tree starting at the return values and descending * through each method argument. Returns an array of * {@link Zend_Server_Reflection_Node}s. * * @return array */ protected function _buildTree() { $returnTree = array(); foreach ((array) $this->_return as $value) { $node = new Zend_Server_Reflection_Node($value); $this->_addTree($node); $returnTree[] = $node; }
return $returnTree; }
/** * Build method signatures * * Builds method signatures using the array of return types and the array of * parameters types * * @param array $return Array of return types * @param string $returnDesc Return value description * @param array $params Array of arguments (each an array of types) * @param array $paramDesc Array of parameter descriptions * @return array */ protected function _buildSignatures($return, $returnDesc, $paramTypes, $paramDesc) { $this->_return = $return; $this->_returnDesc = $returnDesc; $this->_paramDesc = $paramDesc; $this->_sigParams = $paramTypes; $this->_sigParamsDepth = count($paramTypes); $signatureTrees = $this->_buildTree(); $signatures = array();
$endPoints = array(); foreach ($signatureTrees as $root) { $tmp = $root->getEndPoints(); if (empty($tmp)) { $endPoints = array_merge($endPoints, array($root)); } else { $endPoints = array_merge($endPoints, $tmp); } }
foreach ($endPoints as $node) { if (!$node instanceof Zend_Server_Reflection_Node) { continue; }
$signature = array(); do { array_unshift($signature, $node->getValue()); $node = $node->getParent(); } while ($node instanceof Zend_Server_Reflection_Node);
$signatures[] = $signature; }
// Build prototypes $params = $this->_reflection->getParameters(); foreach ($signatures as $signature) { $return = new Zend_Server_Reflection_ReturnValue(array_shift($signature), $this->_returnDesc); $tmp = array(); foreach ($signature as $key => $type) { $param = new Zend_Server_Reflection_Parameter($params[$key], $type, $this->_paramDesc[$key]); $param->setPosition($key); $tmp[] = $param; }
$this->_prototypes[] = new Zend_Server_Reflection_Prototype($return, $tmp); } }
/** * Use code reflection to create method signatures * * Determines the method help/description text from the function DocBlock * comment. Determines method signatures using a combination of * ReflectionFunction and parsing of DocBlock @param and @return values. * * @param ReflectionFunction $function * @return array */ protected function _reflect() { $function = $this->_reflection; $helpText = ''; $signatures = array(); $returnDesc = ''; $paramCount = $function->getNumberOfParameters(); $paramCountRequired = $function->getNumberOfRequiredParameters(); $parameters = $function->getParameters(); $docBlock = $function->getDocComment();
if (!empty($docBlock)) { // Get help text if (preg_match(':/\*\*\s*\r?\n\s*\*\s(.*?)\r?\n\s*\*(\s@|/):s', $docBlock, $matches)) { $helpText = $matches[1]; $helpText = preg_replace('/(^\s*\*\s)/m', '', $helpText); $helpText = preg_replace('/\r?\n\s*\*\s*(\r?\n)*/s', "\n", $helpText); $helpText = trim($helpText); }
// Get return type(s) and description $return = 'void'; if (preg_match('/@return\s+(\S+)/', $docBlock, $matches)) { $return = explode('|', $matches[1]); if (preg_match('/@return\s+\S+\s+(.*?)(@|\*\/)/s', $docBlock, $matches)) { $value = $matches[1]; $value = preg_replace('/\s?\*\s/m', '', $value); $value = preg_replace('/\s{2,}/', ' ', $value); $returnDesc = trim($value); } }
// Get param types and description if (preg_match_all('/@param\s+([^\s]+)/m', $docBlock, $matches)) { $paramTypesTmp = $matches[1]; if (preg_match_all('/@param\s+\S+\s+(\$^\S+)\s+(.*?)(@|\*\/)/s', $docBlock, $matches)) { $paramDesc = $matches[2]; foreach ($paramDesc as $key => $value) { $value = preg_replace('/\s?\*\s/m', '', $value); $value = preg_replace('/\s{2,}/', ' ', $value); $paramDesc[$key] = trim($value); } } } } else { $helpText = $function->getName(); $return = 'void'; }
// Set method description $this->setDescription($helpText);
// Get all param types as arrays if (!isset($paramTypesTmp) && (0 < $paramCount)) { $paramTypesTmp = array_fill(0, $paramCount, 'mixed'); } elseif (!isset($paramTypesTmp)) { $paramTypesTmp = array(); } elseif (count($paramTypesTmp) < $paramCount) { $start = $paramCount - count($paramTypesTmp); for ($i = $start; $i < $paramCount; ++$i) { $paramTypesTmp[$i] = 'mixed'; } }
// Get all param descriptions as arrays if (!isset($paramDesc) && (0 < $paramCount)) { $paramDesc = array_fill(0, $paramCount, ''); } elseif (!isset($paramDesc)) { $paramDesc = array(); } elseif (count($paramDesc) < $paramCount) { $start = $paramCount - count($paramDesc); for ($i = $start; $i < $paramCount; ++$i) { $paramDesc[$i] = ''; } }
if (count($paramTypesTmp) != $paramCount) { require_once 'Zend/Server/Reflection/Exception.php'; throw new Zend_Server_Reflection_Exception( 'Variable number of arguments is not supported for services (except optional parameters). ' . 'Number of function arguments must correspond to actual number of arguments described in a docblock.'); }
$paramTypes = array(); foreach ($paramTypesTmp as $i => $param) { $tmp = explode('|', $param); if ($parameters[$i]->isOptional()) { array_unshift($tmp, null); } $paramTypes[] = $tmp; }
$this->_buildSignatures($return, $returnDesc, $paramTypes, $paramDesc); }
/** * Proxy reflection calls * * @param string $method * @param array $args * @return mixed */ public function __call($method, $args) { if (method_exists($this->_reflection, $method)) { return call_user_func_array(array($this->_reflection, $method), $args); }
require_once 'Zend/Server/Reflection/Exception.php'; throw new Zend_Server_Reflection_Exception('Invalid reflection method ("' .$method. '")'); }
/** * Retrieve configuration parameters * * Values are retrieved by key from {@link $_config}. Returns null if no * value found. * * @param string $key * @return mixed */ public function __get($key) { if (isset($this->_config[$key])) { return $this->_config[$key]; }
return null; }
/** * Set configuration parameters * * Values are stored by $key in {@link $_config}. * * @param string $key * @param mixed $value * @return void */ public function __set($key, $value) { $this->_config[$key] = $value; }
/** * Set method's namespace * * @param string $namespace * @return void */ public function setNamespace($namespace) { if (empty($namespace)) { $this->_namespace = ''; return; }
if (!is_string($namespace) || !preg_match('/[a-z0-9_\.]+/i', $namespace)) { require_once 'Zend/Server/Reflection/Exception.php'; throw new Zend_Server_Reflection_Exception('Invalid namespace'); }
$this->_namespace = $namespace; }
/** * Return method's namespace * * @return string */ public function getNamespace() { return $this->_namespace; }
/** * Set the description * * @param string $string * @return void */ public function setDescription($string) { if (!is_string($string)) { require_once 'Zend/Server/Reflection/Exception.php'; throw new Zend_Server_Reflection_Exception('Invalid description'); }
$this->_description = $string; }
/** * Retrieve the description * * @return void */ public function getDescription() { return $this->_description; }
/** * Retrieve all prototypes as array of * {@link Zend_Server_Reflection_Prototype Zend_Server_Reflection_Prototypes} * * @return array */ public function getPrototypes() { return $this->_prototypes; }
/** * Retrieve additional invocation arguments * * @return array */ public function getInvokeArguments() { return $this->_argv; }
/** * Wakeup from serialization * * Reflection needs explicit instantiation to work correctly. Re-instantiate * reflection object on wakeup. * * @return void */ public function __wakeup() { if ($this->_reflection instanceof ReflectionMethod) { $class = new ReflectionClass($this->_class); $this->_reflection = new ReflectionMethod($class->newInstance(), $this->getName()); } else { $this->_reflection = new ReflectionFunction($this->getName()); } } }
|