reflection of function decorators

This commit is contained in:
Kacper Donat 2018-08-23 21:43:49 +02:00
parent dcee45e10b
commit e46fbb3cc0
8 changed files with 214 additions and 9 deletions

View File

@ -0,0 +1,16 @@
<?php
/**
* Copyright 2018 Kacper Donat
*
* @author Kacper "Kadet" Donat <kacper@kadet.net>
*
* Full license available in separate LICENSE file
*/
namespace Kadet\Functional\Exception;
class ApplicationException extends FunctionalException
{
}

View File

@ -0,0 +1,16 @@
<?php
/**
* Copyright 2018 Kacper Donat
*
* @author Kacper "Kadet" Donat <kacper@kadet.net>
*
* Full license available in separate LICENSE file
*/
namespace Kadet\Functional\Exception;
class FunctionalException extends \RuntimeException
{
}

View File

@ -0,0 +1,150 @@
<?php
/**
* Copyright 2018 Kacper Donat
*
* @author Kacper "Kadet" Donat <kacper@kadet.net>
*
* Full license available in separate LICENSE file
*/
namespace Kadet\Functional\Reflection;
use function Kadet\Functional\reflect;
class ReflectionDecoratedFunction extends \ReflectionFunction
{
public $reflection;
public $decorated;
public function __construct(callable $decorated)
{
$this->decorated = $decorated;
$this->reflection = reflect($decorated);
}
public function inNamespace()
{
return $this->reflection->inNamespace();
}
public function isClosure()
{
return $this->reflection->isVariadic();
}
public function isDeprecated()
{
return $this->reflection->isDeprecated();
}
public function isInternal()
{
return $this->reflection->isInternal();
}
public function isUserDefined()
{
return $this->reflection->isUserDefined();
}
public function getClosureThis()
{
return $this->reflection->getClosureThis();
}
public function getClosureScopeClass()
{
return $this->reflection->getClosureScopeClass();
}
public function getDocComment()
{
return $this->reflection->getDocComment();
}
public function getEndLine()
{
return $this->reflection->getEndLine();
}
public function getExtension()
{
return $this->reflection->getExtension();
}
public function getExtensionName()
{
return $this->reflection->getExtensionName();
}
public function getFileName()
{
return $this->reflection->getFileName();
}
public function getName()
{
return $this->reflection->getName();
}
public function getNamespaceName()
{
return $this->reflection->getNamespaceName();
}
public function getNumberOfParameters()
{
return $this->reflection->getNumberOfParameters();
}
public function getNumberOfRequiredParameters()
{
return $this->reflection->getNumberOfRequiredParameters();
}
public function getParameters()
{
return $this->reflection->getParameters();
}
public function getReturnType()
{
return $this->reflection->getReturnType();
}
public function getShortName()
{
return $this->reflection->getShortName();
}
public function getStartLine()
{
return $this->reflection->getStartLine();
}
public function getStaticVariables()
{
return $this->reflection->getStaticVariables();
}
public function hasReturnType()
{
return $this->reflection->hasReturnType();
}
public function returnsReference()
{
return $this->reflection->returnsReference();
}
public function isGenerator()
{
return $this->reflection->isGenerator();
}
public function isVariadic()
{
return $this->reflection->isVariadic();
}
}

View File

@ -12,7 +12,7 @@ namespace Kadet\Functional\Reflection;
use Kadet\Functional\Utils\FixedFunction;
class ReflectionFixedFunction extends \ReflectionFunction
class ReflectionFixedFunction extends ReflectionDecoratedFunction
{
public function __construct(FixedFunction $function)
{

View File

@ -13,7 +13,7 @@ namespace Kadet\Functional\Reflection;
use Kadet\Functional\Utils\CurriedFunction;
use Kadet\Functional\Utils\PartiallyAppliedFunction;
class ReflectionPartiallyAppliedFunction extends \ReflectionFunction
class ReflectionPartiallyAppliedFunction extends ReflectionDecoratedFunction
{
public $applied;

View File

@ -32,7 +32,7 @@ class FixedFunction implements Decorator
public function __invoke(...$args)
{
return ($this->fixed)($this)(...$args);
return apply($this->fixed, $this, ...$args);
}
public function getDecorated()

View File

@ -21,11 +21,29 @@ function partial(callable $callable, ...$args): PartiallyAppliedFunction
function apply(callable $callable, ...$args)
{
$threshold = reflect($callable)->getNumberOfRequiredParameters();
try {
$reflection = reflect($callable);
$required = $reflection->getNumberOfRequiredParameters();
$all = $reflection->getNumberOfParameters();
return count($args) >= $threshold
? $callable(...$args)
: partial($callable, ...$args);
switch (true) {
case $reflection->isVariadic():
return partial($callable, ...$args);
case count($args) >= $all:
$applied = $callable(...array_slice($args, 0, $all));
return is_callable($applied) ? apply($applied, ...array_slice($args, $all)) : $applied;
case count($args) >= $required:
return $callable(...$args);
default:
return partial($callable, ...$args);
}
} catch (\ReflectionException $exception) {
// if cannot gather necessary information for intelligent application just use normal one
return $callable(...$args);
}
}
function curry(callable $callable, int $threshold = null, ...$args): CurriedFunction

View File

@ -6,7 +6,6 @@ use Kadet\Functional\Predicate\AllOfPredicate;
use Kadet\Functional\Predicate\AnyOfPredicate;
use Kadet\Functional\Predicate\ClosurePredicate;
use Kadet\Functional\Predicate\ConstantPredicate;
use function Kadet\Functional\Predicates\instance;
use Kadet\Functional\Reflection\ReflectionFixedFunction;
use Kadet\Functional\Reflection\ReflectionPartiallyAppliedFunction;
use Kadet\Functional\Utils\FixedFunction;
@ -71,7 +70,13 @@ function symbol($name = null)
return sprintf("%s(%s)", $name ?: 'symbol', $id);
}
function reflect(callable $callable): \ReflectionFunctionAbstract
/**
* @param callable $callable
*
* @return \ReflectionFunction
* @throws \ReflectionException
*/
function reflect(callable $callable): \ReflectionFunction
{
switch (true) {
case $callable instanceof PartiallyAppliedFunction: