Вход Регистрация
Файл: library/Zend/Server/Reflection/Function/Abstract.php
Строк: 614
<?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-2010 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-2010 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 * @version $Id: Abstract.php 23320 2010-11-12 21:57:29Z alexander $
 */
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, (isset($this->_paramDesc[$key]) ? $this->_paramDesc[$key] : null));
                
$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?ns**s(.*?)r?ns**(s@|/):s'$docBlock$matches))
            {
                
$helpText $matches[1];
                
$helpText preg_replace('/(^s**s)/m'''$helpText);
                
$helpText preg_replace('/r?ns**s*(r?n)*/s'"n"$helpText);
                
$helpText trim($helpText);
            }

            
// Get return type(s) and description
            
$return     'void';
            if (
preg_match('/@returns+(S+)/'$docBlock$matches)) {
                
$return explode('|'$matches[1]);
                if (
preg_match('/@returns+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('/@params+([^s]+)/m'$docBlock$matches)) {
                
$paramTypesTmp $matches[1];
                if (
preg_match_all('/@params+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';

            
// Try and auto-determine type, based on reflection
            
$paramTypesTmp = array();
            foreach (
$parameters as $i => $param) {
                
$paramType 'mixed';
                if (
$param->isArray()) {
                    
$paramType 'array';
                }
                
$paramTypesTmp[$i] = $paramType;
            }
        }

        
// Set method description
        
$this->setDescription($helpText);

        
// Get all param types as arrays
        
if (!isset($paramTypesTmp) && ($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) && ($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 in ' $function->getDeclaringClass()->getName() . '::'
             
$function->getName() . '() must correspond to actual number of arguments described in the '
             
'docblock.');
        }

        
$paramTypes = array();
        foreach (
$paramTypesTmp as $i => $param) {
            
$tmp explode('|'$param);
            if (
$parameters[$i]->isOptional()) {
                
array_unshift($tmpnull);
            }
            
$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());
        }
    }
}
Онлайн: 2
Реклама