restaurer func

This commit is contained in:
Jephté Clain 2024-06-24 10:48:43 +04:00
parent a4b67ec721
commit 11a02002fa
1 changed files with 66 additions and 136 deletions

View File

@ -4,7 +4,6 @@ namespace nur\sery\php;
use Closure; use Closure;
use nur\sery\cl; use nur\sery\cl;
use nur\sery\ref\php\ref_func; use nur\sery\ref\php\ref_func;
use nur\sery\str;
use nur\sery\ValueException; use nur\sery\ValueException;
use ReflectionClass; use ReflectionClass;
use ReflectionFunction; use ReflectionFunction;
@ -12,111 +11,55 @@ use ReflectionMethod;
/** /**
* Class func: outils pour appeler des fonctions et méthodes dynamiquement * Class func: outils pour appeler des fonctions et méthodes dynamiquement
*
* Les formats supportés sont:
* - fonctions globales
* - "func" si function_exists("func")
* - [false, "func", ...]
* - méthodes statiques
* - "::method" méthode à lier à une classe avant l'appel
* - "class::method"
* - ["method"] si !class_exists("method")
* - [null, "method", ...] méthode à lier à une classe avant l'appel
* - ["class", "method", ...]
* - méthodes
* - "->method" méthode à lier à un objet avant l'appel
* - ["method"] si !class_exists("method")
* - [null, "method", ...] méthode à lier à un objet avant l'appel
* - [$object, "method", ...]
* - classes
* - "class" si !function_exists("class")
* - "class::"
* - ["class"] si class_exists("class")
* - ["class", null, ...]
*
* les formes "func" et "class" sont distinguées en vérifiant l'existence de la
* fonction
*
* les formes ["class"] et ["method"] sont distinguées en vérifiant l'existence
* de la classe
*/ */
class func { class func {
/** tester si $value est une chaine non vide */
private static function is_ne($value): bool {
return is_string($value) && strlen($value) > 0;
}
/** /**
* tester si $func est d'une des formes suivantes: * tester si $func est une chaine de la forme "XXX::method" XXX est une
* - "func" si function_exists("func") * chaine quelconque éventuellement vide, ou un tableau de la forme ["method"]
* - [false, "func", ...] * ou [anything, "method", ...]
*
* Avec la forme tableau, "method" ne doit pas contenir le caractère '\', pour
* pouvoir utiliser conjointement {@link is_class()}
*/ */
static final function is_global($func): bool { static final function is_static($func, bool $allowClass=false): bool {
if (self::is_ne($func)) { if (is_string($func)) {
$pos = strpos($func, "::"); $pos = strpos($func, "::");
return $pos === false && function_exists($func); if ($pos === false) return false;
} elseif (is_array($func)) { return $pos + 2 < strlen($func);
return ($func[0] ?? null) === false
&& self::is_ne($func[1] ?? null);
}
return false;
}
static final function fix_global_args(&$func, ?array &$args): bool {
if ($args === null) $args = [];
if (is_array($func)) {
if (count($func) > 2) {
$prefix_args = array_slice($func, 2);
$func = array_slice($func, 1, 1)[0];
$args = array_merge($prefix_args, $args);
} else {
$func = $func[0];
}
return true;
}
return false;
}
/**
* tester si $func est d'une des formes suivantes:
* - "::method"
* - "class::method"
* - ["method"] si !class_exists("method")
* - [anything, "method", ...]
*/
static final function is_static($func): bool {
if (self::is_ne($func)) {
$pos = strpos($func, "::");
return $pos !== false && $pos + 2 < strlen($func);
} elseif (is_array($func) && array_key_exists(0, $func)) { } elseif (is_array($func) && array_key_exists(0, $func)) {
$count = count($func); $count = count($func);
if ($count == 1) { if ($count == 1) {
return self::is_ne($func[0]) && !class_exists($func[0]); if (!is_string($func[0]) || strlen($func[0]) == 0) return false;
} elseif ($count > 1 && array_key_exists(1, $func)) { if (strpos($func[0], "\\") !== false) return false;
return self::is_ne($func[1]); return true;
} elseif ($count > 1) {
if (!array_key_exists(1, $func)) return false;
if (!is_string($func[1]) || strlen($func[1]) == 0) return false;
if (strpos($func[1], "\\") !== false) return false;
return true;
} }
} }
return false; return false;
} }
/** /**
* en assumant que {@link self::is_static()} retourne true: * si $func est une chaine de la forme "::method" alors la remplacer par la
* - si $func est une chaine de la forme "::method" alors la remplacer par la
* chaine "$class::method" * chaine "$class::method"
* - si $func est un tableau de la forme ["method"] ou [null, "method"], alors *
* si $func est un tableau de la forme ["method"] ou [null, "method"], alors
* le remplacer par [$class, "method"] * le remplacer par [$class, "method"]
* *
* on assume que {@link is_static()}($func) retourne true
*
* @return bool true si la correction a été faite * @return bool true si la correction a été faite
*/ */
static final function fix_static(&$func, $class): bool { static final function fix_static(&$func, $class): bool {
if (is_object($class)) $class = get_class($class); if (is_object($class)) $class = get_class($class);
if (is_string($func)) { if (is_string($func) && substr($func, 0, 2) == "::") {
if (substr($func, 0, 2) == "::") { $func = "$class$func";
$func = "$class$func"; return true;
return true; } elseif (is_array($func) && array_key_exists(0, $func)) {
}
} else {
$count = count($func); $count = count($func);
if ($count == 1) { if ($count == 1) {
$func = [$class, $func[0]]; $func = [$class, $func[0]];
@ -130,43 +73,37 @@ class func {
} }
/** tester si $method est une chaine de la forme "->method" */ /** tester si $method est une chaine de la forme "->method" */
private static function isam(&$method, bool $requireArrow=false): bool { private static function isam($method): bool {
if (is_string($method)) { return is_string($method)
if (substr($method, 0, 2) == "->") { && strlen($method) > 2
$method = substr($method, 2); && substr($method, 0, 2) == "->";
} elseif ($requireArrow) {
return false;
}
return strlen($method) > 0;
}
return false;
} }
/** /**
* tester si $func est d'une des formes suivantes: * tester si $func est une chaine de la forme "->method" ou un tableau de la
* - "->method" * forme ["->method", ...] ou [anything, "->method", ...]
* - ["method"] si !class_exists("method")
* - [anything, "method", ...]
*/ */
static final function is_method($func): bool { static final function is_method($func): bool {
if (is_string($func)) { if (is_string($func)) {
return self::isam($func, true); return self::isam($func);
} elseif (is_array($func) && array_key_exists(0, $func)) { } elseif (is_array($func) && array_key_exists(0, $func)) {
$count = count($func); if (self::isam($func[0])) {
if ($count == 1) { # ["->method", ...]
return self::isam($func[0]) && !class_exists($func[0]); return true;
} elseif ($count > 1 && array_key_exists(1, $func)) { }
return self::isam($func[1]); if (array_key_exists(1, $func) && self::isam($func[1])) {
# [anything, "->method", ...]
return true;
} }
} }
return false; return false;
} }
/** /**
* en assumant que {@link self::is_method()} retourne true: * si $func est une chaine de la forme "->method" alors la remplacer par le
* - si $func est une chaine de la forme "->method" alors la remplacer par le
* tableau [$object, "method"] * tableau [$object, "method"]
* - si $func est un tableau de la forme ["method"] ou [anything, "method"], *
* si $func est un tableau de la forme ["->method"] ou [anything, "->method"],
* alors le remplacer par [$object, "method"] * alors le remplacer par [$object, "method"]
* *
* @return bool true si la correction a été faite * @return bool true si la correction a été faite
@ -176,18 +113,14 @@ class func {
if (is_string($func)) { if (is_string($func)) {
if (self::isam($func)) { if (self::isam($func)) {
$func = [$object, $func]; $func = [$object, substr($func, 2)];
return true; return true;
} }
} else { } elseif (is_array($func) && array_key_exists(0, $func)) {
$count = count($func); if (self::isam($func[0])) $func = array_merge([null], $func);
if ($count == 1) { if (count($func) > 1 && array_key_exists(1, $func) && self::isam($func[1])) {
self::isam($func[0]);
$func = [$object, $func[0]];
return true;
} else {
$func[0] = $object; $func[0] = $object;
self::isam($func[1]); $func[1] = substr($func[1], 2);
return true; return true;
} }
} }
@ -423,32 +356,29 @@ class func {
} }
/** /**
* tester si $class est d'une des formes suivantes: * tester si $func est une chaine de la forme "XXX" XXX est une classe
* - "class" si !function_exists("class") * valide, ou un tableau de la forme ["XXX", ...]
* - "class::" *
* - ["class"] si class_exists("class") * NB: il est possible d'avoir {@link is_static()} et {@link is_class()}
* - ["class", null, ...] * vraies pour la même valeur. s'il faut supporter les deux cas, appeler
* {@link is_static()} d'abord, mais dans ce cas, on ne supporte que les
* classes qui sont dans un package
*/ */
static final function is_class($class): bool { static final function is_class($class): bool {
if (self::is_ne($class)) { if (is_string($class)) {
return str::ends_with("::", $class) return class_exists($class);
|| !function_exists($class); } elseif (is_array($class) && array_key_exists(0, $class)) {
} elseif (is_array($class) && self::is_ne($class[0] ?? null)) { return class_exists($class[0]);
$count = count($class);
if ($count == 1) {
return class_exists($class[0]);
} elseif ($count > 1 && array_key_exists(1, $class)) {
return $class[1] === null;
}
} }
return false; return false;
} }
/** /**
* si $class est un tableau de plus de 2 éléments, alors déplacer les éléments * en assumant que {@link is_class()} est vrai, si $class est un tableau de
* supplémentaires au début de $args. par exemple: * plus de 1 éléments, alors déplacer les éléments supplémentaires au début de
* $args. par exemple:
* ~~~ * ~~~
* $class = ["class", null, "arg1", "arg2"]; * $class = ["class", "arg1", "arg2"];
* $args = ["arg3"]; * $args = ["arg3"];
* func::fix_class_args($class, $args) * func::fix_class_args($class, $args)
* # $class === "class" * # $class === "class"
@ -460,8 +390,8 @@ class func {
static final function fix_class_args(&$class, ?array &$args): bool { static final function fix_class_args(&$class, ?array &$args): bool {
if ($args === null) $args = []; if ($args === null) $args = [];
if (is_array($class)) { if (is_array($class)) {
if (count($class) > 2) { if (count($class) > 1) {
$prefix_args = array_slice($class, 2); $prefix_args = array_slice($class, 1);
$class = array_slice($class, 0, 1)[0]; $class = array_slice($class, 0, 1)[0];
$args = array_merge($prefix_args, $args); $args = array_merge($prefix_args, $args);
} else { } else {