modifs.mineures sans commentaires

This commit is contained in:
Jephté Clain 2024-09-11 23:35:46 +04:00
parent 3eb5e3d028
commit 73bfc8ddae
2 changed files with 1038 additions and 608 deletions

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,13 @@
namespace nur\sery\wip\php; namespace nur\sery\wip\php;
use Closure; use Closure;
use nur\config\Ref;
use nur\sery\cv; use nur\sery\cv;
use nur\sery\StateException;
use nur\sery\ValueException;
use ReflectionClass;
use ReflectionFunction;
use ReflectionMethod;
/** /**
* Class func: outils pour appeler fonctions et méthodes dynamiquement * Class func: outils pour appeler fonctions et méthodes dynamiquement
@ -53,42 +59,50 @@ class func {
return true; return true;
} }
private static function is_invalid(?string $m): bool { /**
* vérifier que $func est une fonction simple avec les règles de
* {@link self::verifix_simple()}
*/
static function is_simple($func, bool $strict=true): bool {
return self::verifix_simple($func, $strict);
}
private static function _is_invalid(?string $m): bool {
return $m === null || $m === "" || $m === "::" || $m === "->"; return $m === null || $m === "" || $m === "::" || $m === "->";
} }
private static function is_nfunction(?string $m): bool { private static function _is_nfunction(?string $m): bool {
return strpos($m, "\\") !== false; return strpos($m, "\\") !== false;
} }
private static function parse_static(?string &$m): bool { private static function _parse_static(?string &$m): bool {
$pos = strpos($m, "::"); $pos = strpos($m, "::");
if ($pos === false) return false; if ($pos === false) return false;
$m = substr($m, $pos + 2); $m = substr($m, $pos + 2);
return true; return true;
} }
private static function parse_method(?string &$m): bool { private static function _parse_method(?string &$m): bool {
$pos = strpos($m, "->"); $pos = strpos($m, "->");
if ($pos === false) return false; if ($pos === false) return false;
$m = substr($m, $pos + 2); $m = substr($m, $pos + 2);
return true; return true;
} }
private static function parse_class_s(?string $cs, ?string &$c, ?string &$s): bool { private static function _parse_class_s(?string $cs, ?string &$c, ?string &$s): bool {
if (self::is_invalid($cs) || self::parse_method($cs)) return false; if (self::_is_invalid($cs) || self::_parse_method($cs)) return false;
$pos = strpos($cs, "::"); $pos = strpos($cs, "::");
if ($pos === false) return false; if ($pos === false) return false;
if ($pos === 0) return false; if ($pos === 0) return false;
$tmpc = substr($cs, 0, $pos); $tmpc = substr($cs, 0, $pos);
$cs = substr($cs, $pos + 2); $cs = substr($cs, $pos + 2);
if (self::is_nfunction($cs)) return false; if (self::_is_nfunction($cs)) return false;
[$c, $s] = [$tmpc, cv::vn($cs)]; [$c, $s] = [$tmpc, cv::vn($cs)];
return true; return true;
} }
private static function parse_c_static(?string $cs, ?string &$c, ?string &$s, ?bool &$bound): bool { private static function _parse_c_static(?string $cs, ?string &$c, ?string &$s, ?bool &$bound): bool {
if (self::is_invalid($cs) || self::parse_method($cs)) return false; if (self::_is_invalid($cs) || self::_parse_method($cs)) return false;
$pos = strpos($cs, "::"); $pos = strpos($cs, "::");
if ($pos === false) return false; if ($pos === false) return false;
if ($pos == strlen($cs) - 2) return false; if ($pos == strlen($cs) - 2) return false;
@ -100,7 +114,7 @@ class func {
$bound = false; $bound = false;
} }
$cs = substr($cs, $pos + 2); $cs = substr($cs, $pos + 2);
if (self::is_nfunction($cs)) return false; if (self::_is_nfunction($cs)) return false;
[$c, $s] = [$tmpc, cv::vn($cs)]; [$c, $s] = [$tmpc, cv::vn($cs)];
return true; return true;
} }
@ -124,25 +138,25 @@ class func {
*/ */
static function verifix_static(&$func, bool $strict=true, ?bool &$bound=null): bool { static function verifix_static(&$func, bool $strict=true, ?bool &$bound=null): bool {
if (is_string($func)) { if (is_string($func)) {
if (!self::parse_c_static($func, $c, $f, $bound)) return false; if (!self::_parse_c_static($func, $c, $f, $bound)) return false;
$func = [$c, $f]; $func = [$c, $f];
} elseif (is_array($func)) { } elseif (is_array($func)) {
if (!array_key_exists(0, $func)) return false; if (!array_key_exists(0, $func)) return false;
$c = $func[0]; $c = $func[0];
if ($c === false) return false; if ($c === false) return false;
if (self::parse_class_s($c, $c, $f)) { if (self::_parse_class_s($c, $c, $f)) {
$func[0] = $c; $func[0] = $c;
if ($f !== null) { if ($f !== null) {
# ["class::method"] --> ["class", "method"] # ["class::method"] --> ["class", "method"]
array_splice($func, 1, 0, [$f]); array_splice($func, 1, 0, [$f]);
} }
$bound = true; $bound = true;
} elseif (self::parse_c_static($c, $c, $f, $bound)) { } elseif (self::_parse_c_static($c, $c, $f, $bound)) {
# ["::method"] --> [null, "method"] # ["::method"] --> [null, "method"]
array_splice($func, 0, 0, [null]); array_splice($func, 0, 0, [null]);
$func[1] = $f; $func[1] = $f;
} else { } else {
if (self::is_invalid($c)) $c = null; if (self::_is_invalid($c)) $c = null;
$func[0] = $c; $func[0] = $c;
$bound = is_string($c); $bound = is_string($c);
} }
@ -150,18 +164,18 @@ class func {
if (!array_key_exists(1, $func)) return false; if (!array_key_exists(1, $func)) return false;
$f = $func[1]; $f = $func[1];
if (!is_string($f)) return false; if (!is_string($f)) return false;
if (self::parse_c_static($f, $rc, $f, $rbound)) { if (self::_parse_c_static($f, $rc, $f, $rbound)) {
if ($rc !== null && $c === null) { if ($rc !== null && $c === null) {
$c = $rc; $c = $rc;
$bound = $rbound; $bound = $rbound;
} }
} elseif (self::is_invalid($f)) { } elseif (self::_is_invalid($f)) {
return false; return false;
} elseif (self::is_nfunction($f)) { } elseif (self::_is_nfunction($f)) {
return false; return false;
} elseif (self::parse_method($f)) { } elseif (self::_parse_method($f)) {
return false; return false;
} elseif (self::parse_static($f)) { } elseif (self::_parse_static($f)) {
} }
$func[1] = $f; $func[1] = $f;
} else { } else {
@ -171,20 +185,28 @@ class func {
return true; return true;
} }
private static function parse_class_m(?string $cm, ?string &$c, ?string &$m): bool { /**
if (self::is_invalid($cm) || self::parse_static($cm)) return false; * vérifier que $func est une méthode statique avec les règles de
* {@link self::verifix_static()}
*/
static function is_static($func, bool $strict=true, ?bool &$bound=null): bool {
return self::verifix_static($func, $strict, $bound);
}
private static function _parse_class_m(?string $cm, ?string &$c, ?string &$m): bool {
if (self::_is_invalid($cm) || self::_parse_static($cm)) return false;
$pos = strpos($cm, "->"); $pos = strpos($cm, "->");
if ($pos === false) return false; if ($pos === false) return false;
if ($pos === 0) return false; if ($pos === 0) return false;
$tmpc = substr($cm, 0, $pos); $tmpc = substr($cm, 0, $pos);
$cm = substr($cm, $pos + 2); $cm = substr($cm, $pos + 2);
if (self::is_nfunction($cm)) return false; if (self::_is_nfunction($cm)) return false;
[$c, $m] = [$tmpc, cv::vn($cm)]; [$c, $m] = [$tmpc, cv::vn($cm)];
return true; return true;
} }
private static function parse_c_method(?string $cm, ?string &$c, ?string &$m, ?bool &$bound): bool { private static function _parse_c_method(?string $cm, ?string &$c, ?string &$m, ?bool &$bound): bool {
if (self::is_invalid($cm) || self::parse_static($cm)) return false; if (self::_is_invalid($cm) || self::_parse_static($cm)) return false;
$pos = strpos($cm, "->"); $pos = strpos($cm, "->");
if ($pos === false) return false; if ($pos === false) return false;
if ($pos == strlen($cm) - 2) return false; if ($pos == strlen($cm) - 2) return false;
@ -196,7 +218,7 @@ class func {
$bound = false; $bound = false;
} }
$cm = substr($cm, $pos + 2); $cm = substr($cm, $pos + 2);
if (self::is_nfunction($cm)) return false; if (self::_is_nfunction($cm)) return false;
[$c, $m] = [$tmpc, cv::vn($cm)]; [$c, $m] = [$tmpc, cv::vn($cm)];
return true; return true;
} }
@ -220,25 +242,25 @@ class func {
*/ */
static function verifix_method(&$func, bool $strict=true, ?bool &$bound=null): bool { static function verifix_method(&$func, bool $strict=true, ?bool &$bound=null): bool {
if (is_string($func)) { if (is_string($func)) {
if (!self::parse_c_method($func, $c, $f, $bound)) return false; if (!self::_parse_c_method($func, $c, $f, $bound)) return false;
$func = [$c, $f]; $func = [$c, $f];
} elseif (is_array($func)) { } elseif (is_array($func)) {
if (!array_key_exists(0, $func)) return false; if (!array_key_exists(0, $func)) return false;
$c = $func[0]; $c = $func[0];
if ($c === false) return false; if ($c === false) return false;
if (self::parse_class_m($c, $c, $f)) { if (self::_parse_class_m($c, $c, $f)) {
$func[0] = $c; $func[0] = $c;
if ($f !== null) { if ($f !== null) {
# ["class->method"] --> ["class", "method"] # ["class->method"] --> ["class", "method"]
array_splice($func, 1, 0, [$f]); array_splice($func, 1, 0, [$f]);
} }
$bound = true; $bound = true;
} elseif (self::parse_c_method($c, $c, $f, $bound)) { } elseif (self::_parse_c_method($c, $c, $f, $bound)) {
# ["->method"] --> [null, "method"] # ["->method"] --> [null, "method"]
array_splice($func, 0, 0, [null]); array_splice($func, 0, 0, [null]);
$func[1] = $f; $func[1] = $f;
} else { } else {
if (self::is_invalid($c)) $c = null; if (self::_is_invalid($c)) $c = null;
$func[0] = $c; $func[0] = $c;
$bound = is_string($c); $bound = is_string($c);
} }
@ -246,18 +268,18 @@ class func {
if (!array_key_exists(1, $func)) return false; if (!array_key_exists(1, $func)) return false;
$f = $func[1]; $f = $func[1];
if (!is_string($f)) return false; if (!is_string($f)) return false;
if (self::parse_c_method($f, $rc, $f, $rbound)) { if (self::_parse_c_method($f, $rc, $f, $rbound)) {
if ($rc !== null && $c === null) { if ($rc !== null && $c === null) {
$c = $rc; $c = $rc;
$bound = $rbound; $bound = $rbound;
} }
} elseif (self::is_invalid($f)) { } elseif (self::_is_invalid($f)) {
return false; return false;
} elseif (self::is_nfunction($f)) { } elseif (self::_is_nfunction($f)) {
return false; return false;
} elseif (self::parse_static($f)) { } elseif (self::_parse_static($f)) {
return false; return false;
} elseif (self::parse_method($f)) { } elseif (self::_parse_method($f)) {
} }
$func[1] = $f; $func[1] = $f;
} else { } else {
@ -266,16 +288,200 @@ class func {
if ($strict && $bound && !method_exists($c, $f)) return false; if ($strict && $bound && !method_exists($c, $f)) return false;
return true; return true;
} }
/**
* vérifier que $func est une méthode non statique avec les règles de
* {@link self::verifix_method()}
*/
static function is_method($func, bool $strict=true, ?bool &$bound=null): bool {
return self::verifix_method($func, $strict, $bound);
}
static function verifix_cons(&$func): bool { static function verifix_cons(&$func, bool $strict=true): bool {
if (is_string($func)) { if (is_string($func)) {
return true;
} elseif (is_array($func)) { } elseif (is_array($func)) {
return true;
} else { } else {
return false; return false;
} }
return false;#XXX
}
static function with($func, bool $strict=true): self {
if ($func instanceof Closure) {
return new self($func);
} elseif (self::verifix_simple($func, $strict)) {
return new self($func);
} elseif (self::verifix_cons($func, $strict)) {
return new self($func);
} else {
if (self::verifix_static($func, $strict, $bound)) {
} elseif (self::verifix_method($func, $strict, $bound)) {
} else {
throw ValueException::invalid_type($func, "callable");
}
if (!$bound) throw ValueException::invalid_value($func, null, "is not bound");
return new self($func);
}
}
static function call($func, ...$args) {
return self::with($func)->invoke($args);
}
static function with_object($func, object $object, bool $rebind=false, bool $strict=true): self {
if ($func instanceof Closure) {
return new self($func);
} elseif (self::verifix_simple($func, $strict)) {
return new self($func);
} elseif (self::verifix_cons($func, $strict)) {
return new self($func);
} else {
if (self::verifix_method($func, $strict, $bound)) {
} elseif (self::verifix_static($func, $strict, $bound)) {
} else {
throw ValueException::invalid_type($func, "callable");
}
if (!$bound || $rebind) $func[0] = $object;
return new self($func);
}
}
static function with_class($func, $class, bool $rebind=false, bool $strict=true): self {
if ($func instanceof Closure) {
return new self($func);
} elseif (self::verifix_simple($func, $strict)) {
return new self($func);
} elseif (self::verifix_cons($func, $strict)) {
return new self($func);
} else {
if (self::verifix_method($func, $strict, $bound)) {
} elseif (self::verifix_static($func, $strict, $bound)) {
} else {
throw ValueException::invalid_type($func, "callable");
}
if (!$bound || $rebind) {
if (is_object($class)) $class = get_class($class);
$func[0] = $class;
}
return new self($func);
}
}
#############################################################################
const TYPE_CLOSURE = 0, TYPE_SIMPLE = 1, TYPE_STATIC = 2, TYPE_METHOD = 3, TYPE_CLASS = 4;
function __construct($func) {
$object = null;
$prefixArgs = [];
if ($func instanceof Closure) {
$type = self::TYPE_CLOSURE;
$reflection = new ReflectionFunction($func);
$object = $func;
} elseif ($func instanceof ReflectionFunction) {
$type = self::TYPE_SIMPLE;
$reflection = $func;
} elseif ($func instanceof ReflectionMethod) {
$type = self::TYPE_STATIC;
$reflection = $func;
} elseif ($func instanceof ReflectionClass) {
$type = self::TYPE_CLASS;
$reflection = $func;
} elseif (is_array($func)) {
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;
$reflection = new ReflectionFunction($f);
} elseif ($f === false) {
# classe
$type = self::TYPE_CLASS;
$reflection = new ReflectionClass($c);
} elseif ($c !== null) {
# methode
$reflection = new ReflectionMethod($func);
if (is_object($c)) {
$type = self::TYPE_METHOD;
$object = $c;
} else {
$type = self::TYPE_STATIC;
}
} else {
throw new StateException("invalid func");
}
} else {
throw new StateException("invalid func");
}
if ($reflection instanceof ReflectionClass) {
$constructor = $reflection->getConstructor();
if ($constructor === null) {
$variadic = false;
$minArgs = $maxArgs = 0;
} else {
$variadic = $constructor->isVariadic();
$minArgs = $constructor->getNumberOfRequiredParameters();
$maxArgs = $constructor->getNumberOfParameters();
}
} else {
$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 invoke(?array $args=null) {
$args = array_merge($this->prefixArgs, $args ?? []);
if (!$this->variadic) $args = array_slice($args, 0, $this->maxArgs);
$minArgs = $this->minArgs;
while (count($args) < $minArgs) $args[] = null;
switch ($this->type) {
case self::TYPE_CLOSURE:
/** @var Closure $closure */
$closure = $this->object;
return $closure(...$args);
case self::TYPE_SIMPLE:
case self::TYPE_STATIC:
/** @var ReflectionFunction $function */
$function = $this->reflection;
return $function->invoke(...$args);
case self::TYPE_METHOD:
/** @var ReflectionMethod $method */
$method = $this->reflection;
return $method->invoke($this->object, ...$args);
case self::TYPE_CLASS:
/** @var ReflectionClass $class */
$class = $this->reflection;
return $class->newInstance(...$args);
}
} }
} }