nur-sery/wip/php/func.php

197 lines
5.9 KiB
PHP

<?php
namespace nur\sery\wip\php;
use Closure;
use nur\sery\cv;
/**
* Class func: outils pour appeler fonctions et méthodes dynamiquement
*
* les fonctions supportées sont:
* - fonctions simples (globales ou dans un namespace)
* - fonctions statiques
* - méthodes
* - Closure
* - constructeur (l'appel de cette "fonction" provoque l'instanciation d'un
* objet)
*
* les fonctions statiques et les méthodes peuvent être liées (associées à une
* classe ou à un objet) ou non liées (il faut les lier avant de pouvoir les
* utiliser)
*/
class func {
/**
* vérifier que $func est une fonction simple et la normaliser le cas échéant.
* retourner true si c'est une fonction simple, false sinon
*
* les formes suivantes sont supportées:
* - "function" si une classe du même nom n'existe pas déjà
* - [false, "function", ...$args] c'est la forme normalisée
*
* @param bool $strict vérifier l'inexistence de la classe et l'existence de
* la fonction (ne pas uniquement faire une vérification syntaxique)
*/
static function verifix_simple(&$func, bool $strict=true): bool {
if (is_string($func)) {
$func = [false, $func];
} elseif (is_array($func)) {
if (!array_key_exists(0, $func)) return false;
if ($func[0] !== false) return false;
if (!array_key_exists(1, $func)) return false;
if (!is_string($func[1])) return false;
} else {
return false;
}
$f = $func[1];
if ($f === "") return false;
if (strpos($f, "::") !== false) return false;
if (strpos($f, "->") !== false) return false;
if ($strict) {
if (class_exists($f)) return false;
if (!function_exists($f)) return false;
}
return true;
}
private static function is_invalid(?string $m): bool {
return $m === null || $m === "" || $m === "::" || $m === "->";
}
private static function is_nfunction(?string $m): bool {
return strpos($m, "\\") !== false;
}
private static function parse_static(?string &$m): bool {
$pos = strpos($m, "::");
if ($pos === false) return false;
$m = substr($m, $pos + 2);
return true;
}
private static function parse_method(?string &$m): bool {
$pos = strpos($m, "->");
if ($pos === false) return false;
$m = substr($m, $pos + 2);
return true;
}
private static function parse_class_m(?string $cm, ?string &$c, ?string &$m): bool {
if (self::is_invalid($cm) || self::parse_method($cm)) return false;
$pos = strpos($cm, "::");
if ($pos === false) return false;
if ($pos === 0) return false;
$tmpc = substr($cm, 0, $pos);
$cm = substr($cm, $pos + 2);
if (self::is_nfunction($cm)) return false;
[$c, $m] = [$tmpc, cv::vn($cm)];
return true;
}
private static function parse_c_method(?string $cm, ?string &$c, ?string &$m, ?bool &$bound): bool {
if (self::is_invalid($cm) || self::parse_method($cm)) return false;
$pos = strpos($cm, "::");
if ($pos === false) return false;
if ($pos == strlen($cm) - 2) return false;
if ($pos > 0) {
$tmpc = substr($cm, 0, $pos);
$bound = true;
} else {
$tmpc = null;
$bound = false;
}
$cm = substr($cm, $pos + 2);
if (self::is_nfunction($cm)) return false;
[$c, $m] = [$tmpc, cv::vn($cm)];
return true;
}
/**
* vérifier que $func est une fonction statique, et la normaliser le cas
* échéant. retourner true si c'est une fonction statique, false sinon
*
* les formes suivantes sont supportées (XXX étant null ou n'importe quelle
* valeur scalaire de n'importe quel type)
* - "XXX::function"
* - ["XXX::function", ...$args]
* - [XXX, "::function", ...$args]
* - [XXX, "function", ...$args] c'est la forme normalisée
*
* Si XXX est une classe, la fonction statique est liée. sinon, elle doit être
* liée à une classe avant d'être utilisée
*
* @param bool $strict vérifier l'inexistence de la classe et l'existence de
* la fonction (ne pas uniquement faire une vérification syntaxique)
*/
static function verifix_static(&$func, bool $strict=true, ?bool &$bound=null): bool {
if (is_string($func)) {
if (!self::parse_c_method($func, $c, $f, $bound)) return false;
$func = [$c, $f];
} elseif (is_array($func)) {
if (!array_key_exists(0, $func)) return false;
$c = $func[0];
if (self::parse_class_m($c, $c, $f)) {
$func[0] = $c;
if ($f !== null) {
# ["class::method"] --> ["class", "method"]
array_splice($func, 1, 0, [$f]);
}
$bound = true;
} elseif (self::parse_c_method($c, $c, $f, $bound)) {
# ["::method"] --> [null, "method"]
array_splice($func, 0, 0, [null]);
$func[1] = $f;
} else {
if (self::is_invalid($c)) $c = null;
$func[0] = $c;
$bound = is_string($c);
}
#
if (!array_key_exists(1, $func)) return false;
$f = $func[1];
if (!is_string($f)) return false;
if (self::parse_c_method($f, $rc, $f, $rbound)) {
if ($rc !== null && $c === null) {
$c = $rc;
$bound = $rbound;
}
} elseif (self::is_invalid($f)) {
return false;
} elseif (self::is_nfunction($f)) {
return false;
} elseif (self::parse_method($f)) {
return false;
} elseif (self::parse_static($f)) {
}
$func[1] = $f;
} else {
return false;
}
if ($strict && $bound && !method_exists($c, $f)) return false;
return true;
}
static function verifix_method(&$func): bool {
if (is_string($func)) {
return true;
} elseif (is_array($func)) {
return true;
} else {
return false;
}
}
static function verifix_cons(&$func): bool {
if (is_string($func)) {
return true;
} elseif (is_array($func)) {
return true;
} else {
return false;
}
}
}