PK 5PK8%
LICENSE.mdnu ٘ Copyright (c) 2020 Laminas Project a Series of LF Projects, LLC.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
- Neither the name of Laminas Foundation nor the names of its contributors may
be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
PK 5PF[ [ COPYRIGHT.mdnu ٘ Copyright (c) 2020 Laminas Project a Series of LF Projects, LLC. (https://getlaminas.org/)
PK 5PAé .travis.ymlnu ٘ language: php
cache:
directories:
- $HOME/.composer/cache
env:
global:
- COMPOSER_ARGS="--no-interaction"
- COVERAGE_DEPS="php-coveralls/php-coveralls"
matrix:
fast_finish: true
include:
- php: 5.6
env:
- DEPS=lowest
- php: 5.6
env:
- DEPS=latest
- php: 7
env:
- DEPS=lowest
- php: 7
env:
- DEPS=latest
- php: 7.1
env:
- DEPS=lowest
- php: 7.1
env:
- DEPS=latest
- CS_CHECK=true
- TEST_COVERAGE=true
- php: 7.2
env:
- DEPS=lowest
- php: 7.2
env:
- DEPS=latest
- php: 7.3
env:
- DEPS=lowest
- php: 7.3
env:
- DEPS=latest
before_install:
- if [[ $TEST_COVERAGE != 'true' ]]; then phpenv config-rm xdebug.ini || return 0 ; fi
install:
- travis_retry composer install $COMPOSER_ARGS --ignore-platform-reqs
- if [[ $LEGACY_DEPS != '' ]]; then travis_retry composer update $COMPOSER_ARGS --with-dependencies $LEGACY_DEPS ; fi
- if [[ $DEPS == 'latest' ]]; then travis_retry composer update $COMPOSER_ARGS ; fi
- if [[ $DEPS == 'lowest' ]]; then travis_retry composer update --prefer-lowest --prefer-stable $COMPOSER_ARGS ; fi
- if [[ $TEST_COVERAGE == 'true' ]]; then travis_retry composer require --dev $COMPOSER_ARGS $COVERAGE_DEPS ; fi
- stty cols 120 && composer show
script:
- if [[ $TEST_COVERAGE == 'true' ]]; then composer test-coverage ; else composer test ; fi
- if [[ $CS_CHECK == 'true' ]]; then composer cs-check ; fi
after_script:
- if [[ $TEST_COVERAGE == 'true' ]]; then travis_retry php vendor/bin/php-coveralls -v ; fi
notifications:
email: false
PK 5Px= = .coveralls.ymlnu ٘ coverage_clover: clover.xml
json_path: coveralls-upload.json
PK 5P= phpcs.xmlnu ٘
src
test
PK 5PLe README.mdnu ٘ # laminas-server
[![Build Status](https://travis-ci.com/laminas/laminas-server.svg?branch=master)](https://travis-ci.com/laminas/laminas-server)
[![Coverage Status](https://coveralls.io/repos/github/laminas/laminas-server/badge.svg?branch=master)](https://coveralls.io/github/laminas/laminas-server?branch=master)
The laminas-server family of classes provides functionality for the various server
classes, including `Laminas\XmlRpc\Server` and `Laminas\Json\Server`.
`Laminas\Server\Server` provides an interface that mimics PHP 5’s SoapServer class;
all server classes should implement this interface in order to provide a standard
server API.
- File issues at https://github.com/laminas/laminas-server/issues
- Documentation is at https://docs.laminas.dev/laminas-server/
PK 5P@ݫ
.gitignorenu ٘ /clover.xml
/composer.lock
/coveralls-upload.json
/docs/html/
/laminas-mkdoc-theme.tgz
/laminas-mkdoc-theme/
/phpunit.xml
/vendor/
PK 5P
src/Cache.phpnu ٘ getFunctions());
ErrorHandler::start();
$test = file_put_contents($filename, serialize($methods));
ErrorHandler::stop();
if (0 === $test) {
return false;
}
return true;
}
/**
* Load server definition from a file
*
* Unserializes a stored server definition from $filename. Returns false if
* it fails in any way, true on success.
*
* Useful to prevent needing to build the server definition on each
* request. Sample usage:
*
*
* if (!Laminas\Server\Cache::get($filename, $server)) {
* require_once 'Some/Service/ServiceClass.php';
* require_once 'Another/Service/ServiceClass.php';
*
* // Attach Some\Service\ServiceClass with namespace 'some'
* $server->attach('Some\Service\ServiceClass', 'some');
*
* // Attach Another\Service\ServiceClass with namespace 'another'
* $server->attach('Another\Service\ServiceClass', 'another');
*
* Laminas\Server\Cache::save($filename, $server);
* }
*
* $response = $server->handle();
* echo $response;
*
*
* @param string $filename
* @param \Laminas\Server\Server $server
* @return bool
*/
public static function get($filename, Server $server)
{
if (! is_string($filename) || ! file_exists($filename) || ! is_readable($filename)) {
return false;
}
ErrorHandler::start();
$dispatch = file_get_contents($filename);
ErrorHandler::stop();
if (false === $dispatch) {
return false;
}
ErrorHandler::start(E_NOTICE);
$dispatchArray = unserialize($dispatch);
ErrorHandler::stop();
if (false === $dispatchArray) {
return false;
}
$server->loadFunctions($dispatchArray);
return true;
}
/**
* Remove a cache file
*
* @param string $filename
* @return bool
*/
public static function delete($filename)
{
if (is_string($filename) && file_exists($filename)) {
unlink($filename);
return true;
}
return false;
}
/**
* @var array|Definition $methods
* @return array|Definition
*/
private static function createDefinition($methods)
{
if ($methods instanceof Definition) {
return self::createDefinitionFromMethodsDefinition($methods);
}
if (is_array($methods)) {
return self::createDefinitionFromMethodsArray($methods);
}
return $methods;
}
/**
* @return Definition
*/
private static function createDefinitionFromMethodsDefinition(Definition $methods)
{
$definition = new Definition();
foreach ($methods as $method) {
if (in_array($method->getName(), static::$skipMethods, true)) {
continue;
}
$definition->addMethod($method);
}
return $definition;
}
/**
* @return array
*/
private static function createDefinitionFromMethodsArray(array $methods)
{
foreach (array_keys($methods) as $methodName) {
if (in_array($methodName, static::$skipMethods, true)) {
unset($methods[$methodName]);
}
}
return $methods;
}
}
PK 5P8F0 0 src/Definition.phpnu ٘ setMethods($methods);
}
}
/**
* Set flag indicating whether or not overwriting existing methods is allowed
*
* @param mixed $flag
* @return \Laminas\Server\Definition
*/
public function setOverwriteExistingMethods($flag)
{
$this->overwriteExistingMethods = (bool) $flag;
return $this;
}
/**
* Add method to definition
*
* @param array|\Laminas\Server\Method\Definition $method
* @param null|string $name
* @return \Laminas\Server\Definition
* @throws \Laminas\Server\Exception\InvalidArgumentException if duplicate or invalid method provided
*/
public function addMethod($method, $name = null)
{
if (is_array($method)) {
$method = new Method\Definition($method);
} elseif (! $method instanceof Method\Definition) {
throw new Exception\InvalidArgumentException('Invalid method provided');
}
if (is_numeric($name)) {
$name = null;
}
if (null !== $name) {
$method->setName($name);
} else {
$name = $method->getName();
}
if (null === $name) {
throw new Exception\InvalidArgumentException('No method name provided');
}
if (! $this->overwriteExistingMethods && array_key_exists($name, $this->methods)) {
throw new Exception\InvalidArgumentException(sprintf('Method by name of "%s" already exists', $name));
}
$this->methods[$name] = $method;
return $this;
}
/**
* Add multiple methods
*
* @param array $methods Array of \Laminas\Server\Method\Definition objects or arrays
* @return \Laminas\Server\Definition
*/
public function addMethods(array $methods)
{
foreach ($methods as $key => $method) {
$this->addMethod($method, $key);
}
return $this;
}
/**
* Set all methods at once (overwrite)
*
* @param array $methods Array of \Laminas\Server\Method\Definition objects or arrays
* @return \Laminas\Server\Definition
*/
public function setMethods(array $methods)
{
$this->clearMethods();
$this->addMethods($methods);
return $this;
}
/**
* Does the definition have the given method?
*
* @param string $method
* @return bool
*/
public function hasMethod($method)
{
return array_key_exists($method, $this->methods);
}
/**
* Get a given method definition
*
* @param string $method
* @return null|\Laminas\Server\Method\Definition
*/
public function getMethod($method)
{
if ($this->hasMethod($method)) {
return $this->methods[$method];
}
return false;
}
/**
* Get all method definitions
*
* @return array Array of \Laminas\Server\Method\Definition objects
*/
public function getMethods()
{
return $this->methods;
}
/**
* Remove a method definition
*
* @param string $method
* @return \Laminas\Server\Definition
*/
public function removeMethod($method)
{
if ($this->hasMethod($method)) {
unset($this->methods[$method]);
}
return $this;
}
/**
* Clear all method definitions
*
* @return \Laminas\Server\Definition
*/
public function clearMethods()
{
$this->methods = [];
return $this;
}
/**
* Cast definition to an array
*
* @return array
*/
public function toArray()
{
$methods = [];
foreach ($this->getMethods() as $key => $method) {
$methods[$key] = $method->toArray();
}
return $methods;
}
/**
* Countable: count of methods
*
* @return int
*/
public function count()
{
return count($this->methods);
}
/**
* Iterator: current item
*
* @return Method\Definition
*/
public function current()
{
return current($this->methods);
}
/**
* Iterator: current item key
*
* @return int|string
*/
public function key()
{
return key($this->methods);
}
/**
* Iterator: advance to next method
*
* @return Method\Definition
*/
public function next()
{
return next($this->methods);
}
/**
* Iterator: return to first method
*
* @return void
*/
public function rewind()
{
reset($this->methods);
}
/**
* Iterator: is the current index valid?
*
* @return bool
*/
public function valid()
{
return (bool) $this->current();
}
}
PK 5P ̊ " src/Exception/RuntimeException.phpnu ٘ 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 PhpReflectionMethod) {
$this->class = $r->getDeclaringClass()->getName();
}
$this->name = $r->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 \Laminas\Server\Reflection\Node $parent
* @param int $level
* @return void
*/
protected function addTree(Node $parent, $level = 0)
{
if ($level >= $this->sigParamsDepth) {
return;
}
foreach ($this->sigParams[$level] as $value) {
$node = new 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 \Laminas\Server\Reflection\Node}s.
*
* @return array
*/
protected function buildTree()
{
$returnTree = [];
foreach ($this->return as $value) {
$node = new 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 $paramTypes 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 = [];
$endPoints = [];
foreach ($signatureTrees as $root) {
$tmp = $root->getEndPoints();
if (empty($tmp)) {
$endPoints = array_merge($endPoints, [$root]);
} else {
$endPoints = array_merge($endPoints, $tmp);
}
}
foreach ($endPoints as $node) {
if (! $node instanceof Node) {
continue;
}
$signature = [];
do {
array_unshift($signature, $node->getValue());
$node = $node->getParent();
} while ($node instanceof Node);
$signatures[] = $signature;
}
// Build prototypes
$params = $this->reflection->getParameters();
foreach ($signatures as $signature) {
$return = new ReflectionReturnValue(array_shift($signature), $this->returnDesc);
$tmp = [];
foreach ($signature as $key => $type) {
$param = new ReflectionParameter(
$params[$key],
$type,
(isset($this->paramDesc[$key]) ? $this->paramDesc[$key] : null)
);
$param->setPosition($key);
$tmp[] = $param;
}
$this->prototypes[] = new 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.
*
* @throws Exception\RuntimeException
* @return array
*/
protected function reflect()
{
$function = $this->reflection;
$paramCount = $function->getNumberOfParameters();
$parameters = $function->getParameters();
if (! $this->docComment) {
$this->docComment = $function->getDocComment();
}
$scanner = new DocBlockReflection(($this->docComment) ? : '/***/');
$helpText = $scanner->getLongDescription();
/* @var \Laminas\Code\Reflection\DocBlock\Tag\ParamTag[] $paramTags */
$paramTags = $scanner->getTags('param');
/* @var \Laminas\Code\Reflection\DocBlock\Tag\ReturnTag $returnTag */
$returnTag = $scanner->getTag('return');
if (empty($helpText)) {
$helpText = $scanner->getShortDescription();
if (empty($helpText)) {
$helpText = $function->getName();
}
}
$this->setDescription($helpText);
if ($returnTag) {
$return = [];
$returnDesc = $returnTag->getDescription();
foreach ($returnTag->getTypes() as $type) {
$return[] = $type;
}
} else {
$return = ['void'];
$returnDesc = '';
}
$paramTypesTmp = [];
$paramDesc = [];
if (empty($paramTags)) {
foreach ($parameters as $param) {
$paramTypesTmp[] = [($param->isArray()) ? 'array' : 'mixed'];
$paramDesc[] = '';
}
} else {
$paramDesc = [];
foreach ($paramTags as $paramTag) {
$paramTypesTmp[] = $paramTag->getTypes();
$paramDesc[] = ($paramTag->getDescription()) ? : '';
}
}
// Get all param types as arrays
$nParamTypesTmp = count($paramTypesTmp);
if ($nParamTypesTmp < $paramCount) {
$start = $paramCount - $nParamTypesTmp;
for ($i = $start; $i < $paramCount; ++$i) {
$paramTypesTmp[$i] = ['mixed'];
$paramDesc[$i] = '';
}
} elseif ($nParamTypesTmp != $paramCount) {
throw new Exception\RuntimeException(
'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 = [];
foreach ($paramTypesTmp as $i => $param) {
if ($parameters[$i]->isOptional()) {
array_unshift($param, null);
}
$paramTypes[] = $param;
}
$this->buildSignatures($return, $returnDesc, $paramTypes, $paramDesc);
}
/**
* Proxy reflection calls
*
* @param string $method
* @param array $args
* @throws Exception\BadMethodCallException
* @return mixed
*/
public function __call($method, $args)
{
if (method_exists($this->reflection, $method)) {
return call_user_func_array([$this->reflection, $method], $args);
}
throw new Exception\BadMethodCallException('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;
}
/**
* 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
* @throws Exception\InvalidArgumentException
* @return void
*/
public function setNamespace($namespace)
{
if (empty($namespace)) {
$this->namespace = '';
return;
}
if (! is_string($namespace) || ! preg_match('/[a-z0-9_\.]+/i', $namespace)) {
throw new Exception\InvalidArgumentException('Invalid namespace');
}
$this->namespace = $namespace;
}
/**
* Return method's namespace
*
* @return string
*/
public function getNamespace()
{
return $this->namespace;
}
/**
* Set the description
*
* @param string $string
* @throws Exception\InvalidArgumentException
* @return void
*/
public function setDescription($string)
{
if (! is_string($string)) {
throw new Exception\InvalidArgumentException('Invalid description');
}
$this->description = $string;
}
/**
* Retrieve the description
*
* @return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Retrieve all prototypes as array of
* {@link \Laminas\Server\Reflection\Prototype}s
*
* @return Prototype[]
*/
public function getPrototypes()
{
return $this->prototypes;
}
/**
* Retrieve additional invocation arguments
*
* @return array
*/
public function getInvokeArguments()
{
return $this->argv;
}
/**
* @return string[]
*/
public function __sleep()
{
$serializable = [];
foreach ($this as $name => $value) {
if ($value instanceof PhpReflectionFunction
|| $value instanceof PhpReflectionMethod
) {
continue;
}
$serializable[] = $name;
}
return $serializable;
}
/**
* 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 PhpReflectionMethod) {
$class = new PhpReflectionClass($this->class);
$this->reflection = new PhpReflectionMethod($class->newInstance(), $this->name);
} else {
$this->reflection = new PhpReflectionFunction($this->name);
}
}
}
PK 5P. - src/Reflection/Exception/RuntimeException.phpnu ٘ value = $value;
if (null !== $parent) {
$this->setParent($parent, true);
}
return $this;
}
/**
* Set parent node
*
* @param \Laminas\Server\Reflection\Node $node
* @param bool $new Whether or not the child node is newly created
* and should always be attached
* @return void
*/
public function setParent(Node $node, $new = false)
{
$this->parent = $node;
if ($new) {
$node->attachChild($this);
return;
}
}
/**
* Create and attach a new child node
*
* @param mixed $value
* @access public
* @return \Laminas\Server\Reflection\Node New child node
*/
public function createChild($value)
{
$child = new static($value, $this);
return $child;
}
/**
* Attach a child node
*
* @param \Laminas\Server\Reflection\Node $node
* @return void
*/
public function attachChild(Node $node)
{
$this->children[] = $node;
if ($node->getParent() !== $this) {
$node->setParent($this);
}
}
/**
* Return an array of all child nodes
*
* @return array
*/
public function getChildren()
{
return $this->children;
}
/**
* Does this node have children?
*
* @return bool
*/
public function hasChildren()
{
return count($this->children) > 0;
}
/**
* Return the parent node
*
* @return null|\Laminas\Server\Reflection\Node
*/
public function getParent()
{
return $this->parent;
}
/**
* Return the node's current value
*
* @return mixed
*/
public function getValue()
{
return $this->value;
}
/**
* Set the node value
*
* @param mixed $value
* @return void
*/
public function setValue($value)
{
$this->value = $value;
}
/**
* Retrieve the bottommost nodes of this node's tree
*
* Retrieves the bottommost nodes of the tree by recursively calling
* getEndPoints() on all children. If a child is null, it returns the parent
* as an end point.
*
* @return array
*/
public function getEndPoints()
{
$endPoints = [];
if (! $this->hasChildren()) {
return $endPoints;
}
foreach ($this->children as $child) {
$value = $child->getValue();
if (null === $value) {
$endPoints[] = $this;
} elseif ((null !== $value) && $child->hasChildren()) {
$childEndPoints = $child->getEndPoints();
if (! empty($childEndPoints)) {
$endPoints = array_merge($endPoints, $childEndPoints);
}
} elseif ((null !== $value) && ! $child->hasChildren()) {
$endPoints[] = $child;
}
}
return $endPoints;
}
}
PK 5P˗ % src/Reflection/ReflectionFunction.phpnu ٘ reflection = $reflection;
$this->name = $reflection->getName();
$this->setNamespace($namespace);
foreach ($reflection->getMethods() as $method) {
// Don't aggregate magic methods
if ('__' == substr($method->getName(), 0, 2)) {
continue;
}
if ($method->isPublic()) {
// Get signatures and description
$this->methods[] = new ReflectionMethod($this, $method, $this->getNamespace(), $argv);
}
}
}
/**
* Proxy reflection calls
*
* @param string $method
* @param array $args
* @throws Exception\BadMethodCallException
* @return mixed
*/
public function __call($method, $args)
{
if (method_exists($this->reflection, $method)) {
return call_user_func_array([$this->reflection, $method], $args);
}
throw new Exception\BadMethodCallException('Invalid reflection 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;
}
/**
* 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;
}
/**
* Return array of dispatchable {@link \Laminas\Server\Reflection\ReflectionMethod}s.
*
* @access public
* @return array
*/
public function getMethods()
{
return $this->methods;
}
/**
* Get namespace for this class
*
* @return string
*/
public function getNamespace()
{
return $this->namespace;
}
/**
* Set namespace for this class
*
* @param string $namespace
* @throws Exception\InvalidArgumentException
* @return void
*/
public function setNamespace($namespace)
{
if (empty($namespace)) {
$this->namespace = '';
return;
}
if (! is_string($namespace) || ! preg_match('/[a-z0-9_\.]+/i', $namespace)) {
throw new Exception\InvalidArgumentException('Invalid namespace');
}
$this->namespace = $namespace;
}
/**
* Wakeup from serialization
*
* Reflection needs explicit instantiation to work correctly. Re-instantiate
* reflection object on wakeup.
*
* @return void
*/
public function __wakeup()
{
$this->reflection = new PhpReflectionClass($this->name);
}
/**
* @return string[]
*/
public function __sleep()
{
return ['config', 'methods', 'namespace', 'name'];
}
}
PK 5P~ ~ # src/Reflection/ReflectionMethod.phpnu ٘ classReflection = $class;
$this->reflection = $r;
$classNamespace = $class->getNamespace();
// Determine namespace
if (! empty($namespace)) {
$this->setNamespace($namespace);
} elseif (! empty($classNamespace)) {
$this->setNamespace($classNamespace);
}
// Determine arguments
if (is_array($argv)) {
$this->argv = $argv;
}
// If method call, need to store some info on the class
$this->class = $class->getName();
$this->name = $r->getName();
// Perform some introspection
$this->reflect();
}
/**
* Return the reflection for the class that defines this method
*
* @return \Laminas\Server\Reflection\ReflectionClass
*/
public function getDeclaringClass()
{
return $this->classReflection;
}
/**
* Wakeup from serialization
*
* Reflection needs explicit instantiation to work correctly. Re-instantiate
* reflection object on wakeup.
*
* @return void
*/
public function __wakeup()
{
$this->classReflection = new ReflectionClass(
new \ReflectionClass($this->class),
$this->getNamespace(),
$this->getInvokeArguments()
);
$this->reflection = new \ReflectionMethod($this->classReflection->getName(), $this->name);
}
/**
* {@inheritdoc}
*/
protected function reflect()
{
$docComment = $this->reflection->getDocComment();
if (strpos($docComment, self::INHERIT_TAG) !== false) {
$this->docComment = $this->fetchRecursiveDocComment();
}
parent::reflect();
}
/**
* Fetch all doc comments for inherit values
*
* @return string
*/
private function fetchRecursiveDocComment()
{
$currentMethodName = $this->reflection->getName();
$docCommentList[] = $this->reflection->getDocComment();
// fetch all doc blocks for method from parent classes
$docCommentFetched = $this->fetchRecursiveDocBlockFromParent($this->classReflection, $currentMethodName);
if ($docCommentFetched) {
$docCommentList = array_merge($docCommentList, $docCommentFetched);
}
// fetch doc blocks from interfaces
$interfaceReflectionList = $this->classReflection->getInterfaces();
foreach ($interfaceReflectionList as $interfaceReflection) {
if (! $interfaceReflection->hasMethod($currentMethodName)) {
continue;
}
$docCommentList[] = $interfaceReflection->getMethod($currentMethodName)->getDocComment();
}
$normalizedDocCommentList = array_map(
function ($docComment) {
$docComment = str_replace('/**', '', $docComment);
$docComment = str_replace('*/', '', $docComment);
return $docComment;
},
$docCommentList
);
$docComment = '/**' . implode(PHP_EOL, $normalizedDocCommentList) . '*/';
return $docComment;
}
/**
* Fetch recursive doc blocks from parent classes
*
* @param \ReflectionClass $reflectionClass
* @param string $methodName
*
* @return array|void
*/
private function fetchRecursiveDocBlockFromParent($reflectionClass, $methodName)
{
$docComment = [];
$parentReflectionClass = $reflectionClass->getParentClass();
if (! $parentReflectionClass) {
return;
}
if (! $parentReflectionClass->hasMethod($methodName)) {
return;
}
$methodReflection = $parentReflectionClass->getMethod($methodName);
$docCommentLast = $methodReflection->getDocComment();
$docComment[] = $docCommentLast;
if ($this->isInherit($docCommentLast)) {
if ($docCommentFetched = $this->fetchRecursiveDocBlockFromParent($parentReflectionClass, $methodName)) {
$docComment = array_merge($docComment, $docCommentFetched);
}
}
return $docComment;
}
/**
* Return true if doc block inherit from parent or interface
*
* @param string $docComment
*
* @return bool
*/
private function isInherit($docComment)
{
$isInherit = strpos($docComment, self::INHERIT_TAG) !== false;
return $isInherit;
}
}
PK 5P"S\ \ &