modifs.mineures sans commentaires

This commit is contained in:
Jephté Clain 2024-09-18 17:23:15 +04:00
parent f3c07d7665
commit 3ce2f8e134
2 changed files with 193 additions and 80 deletions

View File

@ -17,6 +17,7 @@ namespace nur\sery\wip\php\impl {
namespace nur\sery\wip\php {
use nulib\tests\TestCase;
use nur\sery\ValueException;
use nur\sery\wip\php\impl\C0;
use nur\sery\wip\php\impl\C1;
use nur\sery\wip\php\impl\SC;
@ -1002,7 +1003,7 @@ namespace nur\sery\wip\php {
self::assertSame([1, 2, 3], func::call("to1v", 1, 2, 3));
self::assertSame([1, 2, 3, 4], func::call("to1v", 1, 2, 3, 4));
}
function testInvokeClass() {
$func = func::with(SC::class);
self::assertInstanceOf(SC::class, $func->invoke());
@ -1010,14 +1011,14 @@ namespace nur\sery\wip\php {
self::assertInstanceOf(SC::class, $func->invoke([1]));
self::assertInstanceOf(SC::class, $func->invoke([1, 2]));
self::assertInstanceOf(SC::class, $func->invoke([1, 2, 3]));
$func = func::with(C0::class);
self::assertInstanceOf(C0::class, $func->invoke());
self::assertInstanceOf(C0::class, $func->invoke([]));
self::assertInstanceOf(C0::class, $func->invoke([1]));
self::assertInstanceOf(C0::class, $func->invoke([1, 2]));
self::assertInstanceOf(C0::class, $func->invoke([1, 2, 3]));
$func = func::with(C1::class);
/** @var C1 $i1 */
$i1 = $func->invoke();
@ -1034,36 +1035,112 @@ namespace nur\sery\wip\php {
$func = func::with([SC::class, "tstatic"]);
self::assertSame(10, $func->invoke());
$func = func::with([SC::class, "::tstatic"]);
self::assertSame(10, $func->invoke());
$func = func::with([null, "tstatic"]);
self::assertException(ValueException::class, function() use ($func) {
$func->invoke();
});
$func = func::with([null, "::tstatic"]);
self::assertException(ValueException::class, function() use ($func) {
$func->invoke();
});
$func = func::with([null, "tstatic"]);
self::assertSame(10, $func->bind(SC::class)->invoke());
$func = func::with([null, "tstatic"]);
self::assertSame(10, $func->bind(new SC())->invoke());
$func = func::with([null, "::tstatic"]);
self::assertSame(10, $func->bind(SC::class)->invoke());
$func = func::with([null, "::tstatic"]);
self::assertSame(10, $func->bind(new SC())->invoke());
$func = func::with([SC::class, "tmethod"]);
self::assertException(ReflectionException::class, function() use ($func) {
$func->invoke();
});
$func = func::with([null, "tstatic"]);
$func = func::with([SC::class, "::tmethod"]);
self::assertException(ReflectionException::class, function() use ($func) {
$func->invoke();
});
$func = func::with([null, "tmethod"]);
self::assertException(ReflectionException::class, function() use ($func) {
self::assertException(ValueException::class, function() use ($func) {
$func->invoke();
});
$func = func::with([null, "::tmethod"]);
self::assertException(ValueException::class, function() use ($func) {
$func->invoke();
});
$func = func::with([null, "tmethod"]);
self::assertException(ReflectionException::class, function() use ($func) {
$func->bind(new SC())->invoke();
});
$func = func::with([null, "::tmethod"]);
self::assertException(ReflectionException::class, function() use ($func) {
$func->bind(new SC())->invoke();
});
}
function testInvokeMethod() {
$func = func::with([SC::class, "tstatic"]);
self::assertSame(10, $func->invoke());
$func = func::with([new SC(), "tstatic"]);
$func = func::with([SC::class, "->tstatic"]);
self::assertSame(10, $func->invoke());
$func = func::with([null, "tstatic"]);
self::assertException(ValueException::class, function() use ($func) {
$func->invoke();
});
$func = func::with([null, "->tstatic"]);
self::assertException(ValueException::class, function() use ($func) {
$func->invoke();
});
$func = func::with([null, "tstatic"]);
self::assertSame(10, $func->bind(new SC())->invoke());
$func = func::with([null, "->tstatic"]);
self::assertSame(10, $func->bind(new SC())->invoke());
$func = func::with([SC::class, "tmethod"]);
self::assertException(ReflectionException::class, function() use ($func) {
$func->invoke();
});
$func = func::with([new SC(), "tmethod"]);
self::assertSame(11, $func->invoke());
$func = func::with([SC::class, "->tmethod"]);
self::assertException(ReflectionException::class, function() use ($func) {
$func->invoke();
});
$func = func::with([null, "tmethod"]);
self::assertException(ValueException::class, function() use ($func) {
$func->invoke();
});
$func = func::with([null, "->tmethod"]);
self::assertException(ValueException::class, function() use ($func) {
$func->invoke();
});
$func = func::with([null, "tmethod"]);
self::assertException(ReflectionException::class, function() use ($func) {
$func->bind(new SC())->invoke();
});
$func = func::with([null, "->tmethod"]);
self::assertSame(11, $func->bind(new SC())->invoke());
}
}
}

View File

@ -433,35 +433,54 @@ class func {
#############################################################################
# func
const TYPE_CLOSURE = 0, TYPE_SIMPLE = 1, TYPE_CLASS = 2, TYPE_STATIC = 3, TYPE_METHOD = 4;
protected static function not_a_callable($func, ?string $reason) {
if ($reason === null) {
$msg = var_export($func, true);
$reason = "$msg: not a callable";
}
return new ValueException($reason);
}
static function with($func, bool $strict=true): self {
if ($func instanceof Closure) {
return new self($func, false, null);
} elseif (self::verifix_function($func, $strict, $reason)) {
return new self($func, false, $reason);
if (!is_array($func)) {
if ($func instanceof Closure) {
return new self(self::TYPE_CLOSURE, $func);
} elseif ($func instanceof ReflectionFunction) {
return new self(self::TYPE_SIMPLE, $func);
} elseif ($func instanceof ReflectionClass) {
return new self(self::TYPE_CLASS, $func);
} elseif ($func instanceof ReflectionMethod) {
return new self(self::TYPE_METHOD, $func, false);
}
}
if (self::verifix_function($func, $strict, $reason)) {
return new self(self::TYPE_SIMPLE, $func, false, $reason);
} elseif (self::verifix_class($func, $strict, $reason)) {
return new self($func, false, $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_STATIC;
} else {
$valid = false;
}
} else {
if (self::verifix_static($func, $strict, $bound, $reason)) {
$type = self::TYPE_STATIC;
} elseif (self::verifix_method($func, $strict, $bound, $reason)) {
$type = self::TYPE_METHOD;
} else {
$valid = false;
}
}
if ($valid) return new self($func, $bound, $reason);
if ($valid) return new self($type, $func, $bound, $reason);
}
if ($reason === null) {
$msg = var_export($func, true);
$reason = "$msg: not a callable";
}
throw new ValueException($reason);
throw self::not_a_callable($func, $reason);
}
static function call($func, ...$args) {
@ -470,54 +489,74 @@ class func {
#############################################################################
const TYPE_CLOSURE = 0, TYPE_SIMPLE = 1, TYPE_CLASS = 2, TYPE_STATIC = 3, TYPE_METHOD = 4;
protected function __construct($func, bool $bound=false, ?string $reason=null) {
protected function __construct(int $type, $func, bool $bound=false, ?string $reason=null) {
$object = null;
$prefixArgs = [];
if ($func instanceof Closure) {
$type = self::TYPE_CLOSURE;
$object = $func;
$reflection = new ReflectionFunction($func);
} elseif ($func instanceof ReflectionFunction) {
$type = self::TYPE_SIMPLE;
if (!is_array($func)) {
$reflection = $func;
} elseif ($func instanceof ReflectionClass) {
$type = self::TYPE_CLASS;
$reflection = $func;
} elseif ($func instanceof ReflectionMethod) {
$type = self::TYPE_STATIC;
$reflection = $func;
} elseif (is_array($func)) {
$func = null;
} else {
if (count($func) > 2) {
$prefixArgs = array_slice($func, 2);
$func = array_slice($func, 0, 2);
}
[$c, $f] = $func;
if ($c === false) {
# fonction simple
$type = self::TYPE_SIMPLE;
switch ($type) {
case self::TYPE_SIMPLE:
$reflection = new ReflectionFunction($f);
} elseif ($f === false) {
# classe
$type = self::TYPE_CLASS;
break;
case self::TYPE_CLASS:
$reflection = new ReflectionClass($c);
} elseif ($c !== null) {
# methode
$reflection = new ReflectionMethod($c, $f);
if (is_object($c)) {
$type = self::TYPE_METHOD;
$object = $c;
break;
case self::TYPE_STATIC:
case self::TYPE_METHOD:
if ($c === null) {
$reflection = null;
} else {
$type = self::TYPE_STATIC;
$reflection = new ReflectionMethod($c, $f);
if (is_object($c)) $object = $c;
}
} else {
throw new StateException("invalid func");
break;
default:
throw StateException::unexpected_state();
}
} else {
throw new StateException("invalid func");
}
if ($reflection instanceof ReflectionClass) {
$this->type = $type;
$this->func = $func;
$this->bound = $bound;
$this->reason = $reason;
$this->object = $object;
$this->prefixArgs = $prefixArgs;
$this->updateReflection($reflection);
}
protected int $type;
protected ?array $func;
protected bool $bound;
protected ?string $reason;
protected ?object $object;
protected array $prefixArgs;
/** @var Closure|ReflectionFunction|ReflectionMethod|ReflectionClass */
protected $reflection;
protected bool $variadic;
protected int $minArgs;
protected int $maxArgs;
protected function updateReflection($reflection): void {
$variadic = false;
$minArgs = $maxArgs = 0;
if ($reflection instanceof Closure) {
} elseif ($reflection instanceof ReflectionClass) {
$constructor = $reflection->getConstructor();
if ($constructor === null) {
$variadic = false;
@ -527,42 +566,36 @@ class func {
$minArgs = $constructor->getNumberOfRequiredParameters();
$maxArgs = $constructor->getNumberOfParameters();
}
} else {
} elseif ($reflection !== null) {
$variadic = $reflection->isVariadic();
$minArgs = $reflection->getNumberOfRequiredParameters();
$maxArgs = $reflection->getNumberOfParameters();
}
$this->type = $type;
$this->reflection = $reflection;
$this->variadic = $variadic;
$this->minArgs = $minArgs;
$this->maxArgs = $maxArgs;
$this->object = $object;
$this->prefixArgs = $prefixArgs;
}
protected int $type;
/** @var ReflectionFunction|ReflectionMethod|ReflectionClass */
protected $reflection;
protected bool $variadic;
protected int $minArgs;
protected int $maxArgs;
protected ?object $object;
protected array $prefixArgs;
function bind($objectOrClass, bool $rebind=false): self {
}
function bindClass($objectOrClass, bool $rebind=false): self {
function bind($object, bool $rebind=false): self {
if ($rebind || !$this->bound) {
switch ($this->type) {
case self::TYPE_STATIC:
if (is_object($object)) $object = get_class($object);
# pas de break, continuer à la section suivante
case self::TYPE_METHOD:
if ($this->reflection === null) {
$this->func[0] = $object;
$this->updateReflection(new ReflectionMethod(...$this->func));
}
break;
}
if (is_object($object)) {
$this->object = $object;
$this->bound = true;
}
}
return $this;
}
function invoke(?array $args=null) {
@ -574,7 +607,7 @@ class func {
switch ($this->type) {
case self::TYPE_CLOSURE:
/** @var Closure $closure */
$closure = $this->object;
$closure = $this->reflection;
return $closure(...$args);
case self::TYPE_SIMPLE:
/** @var ReflectionFunction $function */
@ -584,11 +617,14 @@ class func {
case self::TYPE_METHOD:
/** @var ReflectionMethod $method */
$method = $this->reflection;
if ($method === null) throw self::not_a_callable($this->func, $this->reason);
return $method->invoke($this->object, ...$args);
case self::TYPE_CLASS:
/** @var ReflectionClass $class */
$class = $this->reflection;
return $class->newInstance(...$args);
default:
throw StateException::unexpected_state();
}
}
}