modifs.mineures sans commentaires
This commit is contained in:
parent
db07658392
commit
b7ea1985b3
|
@ -2,6 +2,8 @@
|
|||
namespace nur\sery\php;
|
||||
|
||||
use Closure;
|
||||
use Exception;
|
||||
use nur\sery\A;
|
||||
use nur\sery\cv;
|
||||
use nur\sery\StateException;
|
||||
use nur\sery\ValueException;
|
||||
|
@ -428,8 +430,14 @@ class func {
|
|||
#############################################################################
|
||||
# func
|
||||
|
||||
const TYPE_MASK = 0b11;
|
||||
|
||||
const FLAG_STATIC = 0b100;
|
||||
|
||||
const TYPE_CLOSURE = 0, TYPE_FUNCTION = 1, TYPE_CLASS = 2, TYPE_METHOD = 3;
|
||||
|
||||
const TYPE_STATIC = self::TYPE_METHOD | self::FLAG_STATIC;
|
||||
|
||||
protected static function not_a_callable($func, ?string $reason) {
|
||||
if ($reason === null) {
|
||||
$msg = var_export($func, true);
|
||||
|
@ -438,53 +446,56 @@ class func {
|
|||
return new ValueException($reason);
|
||||
}
|
||||
|
||||
static function with($func, bool $strict=true): self {
|
||||
static function with($func, ?array $args=null, bool $strict=true): self {
|
||||
if (!is_array($func)) {
|
||||
if ($func instanceof Closure) {
|
||||
return new self(self::TYPE_CLOSURE, $func);
|
||||
return new self(self::TYPE_CLOSURE, $func, $args);
|
||||
} elseif ($func instanceof ReflectionFunction) {
|
||||
return new self(self::TYPE_FUNCTION, $func);
|
||||
return new self(self::TYPE_FUNCTION, $func, $args);
|
||||
} elseif ($func instanceof ReflectionClass) {
|
||||
return new self(self::TYPE_CLASS, $func);
|
||||
return new self(self::TYPE_CLASS, $func, $args);
|
||||
} elseif ($func instanceof ReflectionMethod) {
|
||||
return new self(self::TYPE_METHOD, $func, false);
|
||||
return new self(self::TYPE_METHOD, $func, $args, false);
|
||||
}
|
||||
}
|
||||
if (self::verifix_function($func, $strict, $reason)) {
|
||||
return new self(self::TYPE_FUNCTION, $func, false, $reason);
|
||||
return new self(self::TYPE_FUNCTION, $func, $args, false, $reason);
|
||||
} elseif (self::verifix_class($func, $strict, $reason)) {
|
||||
return new self(self::TYPE_CLASS, $func, false, $reason);
|
||||
} else {
|
||||
$valid = true;
|
||||
if (is_array($func) && array_key_exists(0, $func) && is_object($func[0])) {
|
||||
if (self::verifix_method($func, $strict, $bound, $reason)) {
|
||||
$type = self::TYPE_METHOD;
|
||||
} elseif (self::verifix_static($func, $strict, $bound, $reason)) {
|
||||
$type = self::TYPE_METHOD;
|
||||
} else {
|
||||
$valid = false;
|
||||
}
|
||||
} else {
|
||||
if (self::verifix_static($func, $strict, $bound, $reason)) {
|
||||
$type = self::TYPE_METHOD;
|
||||
return new self(self::TYPE_CLASS, $func, $args, false, $reason);
|
||||
} elseif (self::verifix_method($func, $strict, $bound, $reason)) {
|
||||
$type = self::TYPE_METHOD;
|
||||
} else {
|
||||
$valid = false;
|
||||
}
|
||||
}
|
||||
if ($valid) return new self($type, $func, $bound, $reason);
|
||||
return new self(self::TYPE_METHOD, $func, $args, $bound, $reason);
|
||||
} elseif (self::verifix_static($func, $strict, $bound, $reason)) {
|
||||
return new self(self::TYPE_STATIC, $func, $args, $bound, $reason);
|
||||
}
|
||||
throw self::not_a_callable($func, $reason);
|
||||
}
|
||||
|
||||
static function ensure($func, ?array $args=null, bool $strict=true): self {
|
||||
$func = self::with($func, $args, $strict);
|
||||
if (!$func->isBound()) {
|
||||
throw self::not_a_callable($func->func, $func->reason);
|
||||
}
|
||||
return $func;
|
||||
}
|
||||
|
||||
static function check($func, ?array $args=null, bool $strict=true): bool {
|
||||
try {
|
||||
self::ensure($func, $args, $strict);
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static function call($func, ...$args) {
|
||||
return self::with($func)->invoke($args);
|
||||
}
|
||||
|
||||
#############################################################################
|
||||
|
||||
protected function __construct(int $type, $func, bool $bound=false, ?string $reason=null) {
|
||||
protected function __construct(int $type, $func, ?array $args=null, bool $bound=false, ?string $reason=null) {
|
||||
$flags = $type & ~self::TYPE_MASK;
|
||||
$type = $type & self::TYPE_MASK;
|
||||
$object = null;
|
||||
$prefixArgs = [];
|
||||
if (!is_array($func)) {
|
||||
|
@ -515,8 +526,10 @@ class func {
|
|||
throw StateException::unexpected_state();
|
||||
}
|
||||
}
|
||||
A::merge($prefixArgs, $args);
|
||||
|
||||
$this->type = $type;
|
||||
$this->flags = $flags;
|
||||
$this->func = $func;
|
||||
$this->bound = $bound;
|
||||
$this->reason = $reason;
|
||||
|
@ -527,6 +540,8 @@ class func {
|
|||
|
||||
protected int $type;
|
||||
|
||||
protected int $flags;
|
||||
|
||||
protected ?array $func;
|
||||
|
||||
protected bool $bound;
|
||||
|
@ -550,15 +565,19 @@ class func {
|
|||
$variadic = false;
|
||||
$minArgs = $maxArgs = 0;
|
||||
if ($reflection instanceof Closure) {
|
||||
$r = new ReflectionFunction($reflection);
|
||||
$variadic = $r->isVariadic();
|
||||
$minArgs = $r->getNumberOfRequiredParameters();
|
||||
$maxArgs = $r->getNumberOfParameters();
|
||||
} elseif ($reflection instanceof ReflectionClass) {
|
||||
$constructor = $reflection->getConstructor();
|
||||
if ($constructor === null) {
|
||||
$r = $reflection->getConstructor();
|
||||
if ($r === null) {
|
||||
$variadic = false;
|
||||
$minArgs = $maxArgs = 0;
|
||||
} else {
|
||||
$variadic = $constructor->isVariadic();
|
||||
$minArgs = $constructor->getNumberOfRequiredParameters();
|
||||
$maxArgs = $constructor->getNumberOfParameters();
|
||||
$variadic = $r->isVariadic();
|
||||
$minArgs = $r->getNumberOfRequiredParameters();
|
||||
$maxArgs = $r->getNumberOfParameters();
|
||||
}
|
||||
} elseif ($reflection !== null) {
|
||||
$variadic = $reflection->isVariadic();
|
||||
|
@ -571,19 +590,25 @@ class func {
|
|||
$this->maxArgs = $maxArgs;
|
||||
}
|
||||
|
||||
function bind($object, bool $rebind=false): self {
|
||||
function isBound(): bool {
|
||||
if ($this->type !== self::TYPE_METHOD) return true;
|
||||
if ($this->flags & self::FLAG_STATIC) return $this->bound;
|
||||
else return $this->bound && $this->object !== null;
|
||||
}
|
||||
|
||||
function bind($object): self {
|
||||
if ($this->type !== self::TYPE_METHOD) return $this;
|
||||
$bound = $this->bound && $this->object !== null;
|
||||
if ($bound && !$rebind) return $this;
|
||||
|
||||
[$c, $f] = $this->func;
|
||||
if ($this->reflection === null) {
|
||||
$this->func[0] = $c = $object;
|
||||
$this->updateReflection(new ReflectionMethod($c, $f));
|
||||
}
|
||||
if (is_string($c) && is_object($object) && !($object instanceof $c)) {
|
||||
if (is_object($object) && !($this->flags & self::FLAG_STATIC)) {
|
||||
if (is_object($c)) $c = get_class($c);
|
||||
if (is_string($c) && !($object instanceof $c)) {
|
||||
throw ValueException::invalid_type($object, $c);
|
||||
}
|
||||
if (is_object($object)) {
|
||||
$this->object = $object;
|
||||
$this->bound = true;
|
||||
}
|
||||
|
|
|
@ -1007,13 +1007,13 @@ namespace nur\sery\php {
|
|||
$func = func::with(C1::class);
|
||||
/** @var C1 $i1 */
|
||||
$i1 = $func->invoke();
|
||||
self::assertInstanceOf(C1::class, $i1); self::assertSame(null, $i1->first);
|
||||
self::assertInstanceOf(C1::class, $i1); self::assertSame(0, $i1->base);
|
||||
$i1 = $func->invoke([]);
|
||||
self::assertInstanceOf(C1::class, $i1); self::assertSame(null, $i1->first);
|
||||
self::assertInstanceOf(C1::class, $i1); self::assertSame(0, $i1->base);
|
||||
$i1 = $func->invoke([1]);
|
||||
self::assertInstanceOf(C1::class, $i1); self::assertSame(1, $i1->first);
|
||||
self::assertInstanceOf(C1::class, $i1); self::assertSame(1, $i1->base);
|
||||
$i1 = $func->invoke([1, 2]);
|
||||
self::assertInstanceOf(C1::class, $i1); self::assertSame(1, $i1->first);
|
||||
self::assertInstanceOf(C1::class, $i1); self::assertSame(1, $i1->base);
|
||||
}
|
||||
|
||||
private static function invoke_asserts(): array {
|
||||
|
@ -1082,9 +1082,33 @@ namespace nur\sery\php {
|
|||
self::assertException(ReflectionException::class, $bind_ko([null, "->tmethod"], SC::class));
|
||||
|
||||
self::assertSame(11, $bind_ok([null, "tmethod"], $sc));
|
||||
self::assertSame(11, $bind_ok([null, "::tmethod"], $sc));
|
||||
self::assertException(ReflectionException::class, $bind_ko([null, "::tmethod"], $sc));
|
||||
self::assertSame(11, $bind_ok([null, "->tmethod"], $sc));
|
||||
}
|
||||
|
||||
function testArgs() {
|
||||
$func = function(int $a, int $b, int $c): int {
|
||||
return $a + $b + $c;
|
||||
};
|
||||
|
||||
self::assertSame(6, func::call($func, 1, 2, 3));
|
||||
self::assertSame(6, func::call($func, 1, 2, 3, 4));
|
||||
|
||||
self::assertSame(6, func::with($func)->invoke([1, 2, 3]));
|
||||
self::assertSame(6, func::with($func, [1])->invoke([2, 3]));
|
||||
self::assertSame(6, func::with($func, [1, 2])->invoke([3]));
|
||||
self::assertSame(6, func::with($func, [1, 2, 3])->invoke());
|
||||
self::assertSame(6, func::with($func, [1, 2, 3, 4])->invoke());
|
||||
}
|
||||
|
||||
function testRebind() {
|
||||
$func = func::with([C1::class, "tmethod"]);
|
||||
self::assertSame(11, $func->bind(new C1(0))->invoke());
|
||||
self::assertSame(12, $func->bind(new C1(1))->invoke());
|
||||
self::assertException(ValueException::class, function() use ($func) {
|
||||
$func->bind(new C0())->invoke();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1126,18 +1150,18 @@ namespace nur\sery\php\impl {
|
|||
}
|
||||
|
||||
class C1 {
|
||||
function __construct($first) {
|
||||
$this->first = $first;
|
||||
function __construct(int $base=0) {
|
||||
$this->base = $base;
|
||||
}
|
||||
|
||||
public $first;
|
||||
public int $base;
|
||||
|
||||
static function tstatic(): int {
|
||||
return 10;
|
||||
}
|
||||
|
||||
function tmethod(): int {
|
||||
return 11;
|
||||
return 11 + $this->base;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue