modifs.mineures sans commentaires

This commit is contained in:
Jephté Clain 2024-09-12 08:43:19 +04:00
parent 73bfc8ddae
commit 88c0ebf1c2
4 changed files with 480 additions and 242 deletions

View File

@ -10,10 +10,10 @@ namespace nur\sery\wip\php\impl {
namespace nur\sery\wip\php { namespace nur\sery\wip\php {
use nulib\tests\TestCase; use nulib\tests\TestCase;
use nur\sery\wip\php\impl\MyClass; use nur\sery\wip\php\impl\SC;
class funcTest extends TestCase { class funcTest extends TestCase {
const SIMPLE_TESTS = [ const FUNCTION_TESTS = [
# scalaires # scalaires
[null, [null,
false, null, false, null,
@ -63,19 +63,27 @@ namespace nur\sery\wip\php {
false, null, false, null,
false, null, false, null,
], ],
[MyClass::class."::tstatic", ["xxx::tmissing",
false, null, false, null,
false, null, false, null,
], ],
[MyClass::class."->tmethod", ["xxx->tmissing",
false, null, false, null,
false, null, false, null,
], ],
[MyClass::class."::tmissing", [SC::class."::tstatic",
false, null, false, null,
false, null, false, null,
], ],
[MyClass::class."->tmissing", [SC::class."->tmethod",
false, null,
false, null,
],
[SC::class."::tmissing",
false, null,
false, null,
],
[SC::class."->tmissing",
false, null, false, null,
false, null, false, null,
], ],
@ -128,19 +136,27 @@ namespace nur\sery\wip\php {
false, null, false, null,
false, null, false, null,
], ],
[[MyClass::class."::tstatic"], [["xxx::tmissing"],
false, null, false, null,
false, null, false, null,
], ],
[[MyClass::class."->tmethod"], [["xxx->tmissing"],
false, null, false, null,
false, null, false, null,
], ],
[[MyClass::class."::tmissing"], [[SC::class."::tstatic"],
false, null, false, null,
false, null, false, null,
], ],
[[MyClass::class."->tmissing"], [[SC::class."->tmethod"],
false, null,
false, null,
],
[[SC::class."::tmissing"],
false, null,
false, null,
],
[[SC::class."->tmissing"],
false, null, false, null,
false, null, false, null,
], ],
@ -229,53 +245,68 @@ namespace nur\sery\wip\php {
false, null, false, null,
false, null, false, null,
], ],
[[MyClass::class, "tstatic"], [["xxx", "tmissing"],
false, null, false, null,
false, null, false, null,
], ],
[[MyClass::class, "::tstatic"], [["xxx", "::tmissing"],
false, null, false, null,
false, null, false, null,
], ],
[[MyClass::class, "tmethod"], [["xxx", "->tmissing"],
false, null, false, null,
false, null, false, null,
], ],
[[MyClass::class, "->tmethod"], [[SC::class, "tstatic"],
false, null, false, null,
false, null, false, null,
], ],
[[MyClass::class, "tmissing"], [[SC::class, "::tstatic"],
false, null, false, null,
false, null, false, null,
], ],
[[MyClass::class, "::tmissing"], [[SC::class, "tmethod"],
false, null, false, null,
false, null, false, null,
], ],
[[MyClass::class, "->tmissing"], [[SC::class, "->tmethod"],
false, null,
false, null,
],
[[SC::class, "tmissing"],
false, null,
false, null,
],
[[SC::class, "::tmissing"],
false, null,
false, null,
],
[[SC::class, "->tmissing"],
false, null, false, null,
false, null, false, null,
], ],
]; ];
function testSimple() { function testFunction() {
foreach (self::SIMPLE_TESTS as $args) { foreach (self::FUNCTION_TESTS as $args) {
[$func, [$func,
$verifix1, $func1, $verifix1, $func1,
$verifix2, $func2, $verifix2, $func2,
] = $args; ] = $args;
if ($func === ["", "tsimple"]) {
//echo "breakpoint";
}
$workf = $func; $workf = $func;
$msg = var_export($func, true)." (strict)"; $msg = var_export($func, true)." (strict)";
self::assertSame($verifix1, func::verifix_simple($workf, true), "$msg --> verifix"); self::assertSame($verifix1, func::verifix_function($workf, true), "$msg --> verifix");
if ($verifix1) { if ($verifix1) {
self::assertSame($func1, $workf, "$msg --> func"); self::assertSame($func1, $workf, "$msg --> func");
} }
$workf = $func; $workf = $func;
$msg = var_export($func, true)." (lenient)"; $msg = var_export($func, true)." (lenient)";
self::assertSame($verifix2, func::verifix_simple($workf, false), "$msg --> verifix"); self::assertSame($verifix2, func::verifix_function($workf, false), "$msg --> verifix");
if ($verifix2) { if ($verifix2) {
self::assertSame($func2, $workf, "$msg --> func"); self::assertSame($func2, $workf, "$msg --> func");
} }
@ -332,19 +363,27 @@ namespace nur\sery\wip\php {
false, null, null, false, null, null,
false, null, null, false, null, null,
], ],
[MyClass::class."::tstatic", ["xxx::tmissing",
true, true, [MyClass::class, "tstatic"], false, null, null,
true, true, [MyClass::class, "tstatic"], true, true, ["xxx", "tmissing"],
], ],
[MyClass::class."->tmethod", ["xxx->tmissing",
false, null, null, false, null, null,
false, null, null, false, null, null,
], ],
[MyClass::class."::tmissing", [SC::class."::tstatic",
false, null, null, true, true, [SC::class, "tstatic"],
true, true, [MyClass::class, "tmissing"], true, true, [SC::class, "tstatic"],
], ],
[MyClass::class."->tmissing", [SC::class."->tmethod",
false, null, null,
false, null, null,
],
[SC::class."::tmissing",
false, null, null,
true, true, [SC::class, "tmissing"],
],
[SC::class."->tmissing",
false, null, null, false, null, null,
false, null, null, false, null, null,
], ],
@ -397,19 +436,27 @@ namespace nur\sery\wip\php {
false, null, null, false, null, null,
false, null, null, false, null, null,
], ],
[[MyClass::class."::tstatic"], [["xxx::tmissing"],
true, true, [MyClass::class, "tstatic"], false, null, null,
true, true, [MyClass::class, "tstatic"], true, true, ["xxx", "tmissing"],
], ],
[[MyClass::class."->tmethod"], [["xxx->tmissing"],
false, null, null, false, null, null,
false, null, null, false, null, null,
], ],
[[MyClass::class."::tmissing"], [[SC::class."::tstatic"],
false, null, null, true, true, [SC::class, "tstatic"],
true, true, [MyClass::class, "tmissing"], true, true, [SC::class, "tstatic"],
], ],
[[MyClass::class."->tmissing"], [[SC::class."->tmethod"],
false, null, null,
false, null, null,
],
[[SC::class."::tmissing"],
false, null, null,
true, true, [SC::class, "tmissing"],
],
[[SC::class."->tmissing"],
false, null, null, false, null, null,
false, null, null, false, null, null,
], ],
@ -471,58 +518,70 @@ namespace nur\sery\wip\php {
false, null, null, false, null, null,
], ],
[["", "tsimple"], [["", "tsimple"],
true, false, [null, "tsimple"], false, null, null,
true, false, [null, "tsimple"], false, null, null,
], ],
[["", 'nur\sery\wip\php\impl\ntsimple'], [["", 'nur\sery\wip\php\impl\ntsimple'],
false, null, null, false, null, null,
false, null, null, false, null, null,
], ],
[["", "tmissing"], [["", "tmissing"],
true, false, [null, "tmissing"], false, null, null,
true, false, [null, "tmissing"], false, null, null,
], ],
[["", "::tstatic"], [["", "::tstatic"],
true, false, [null, "tstatic"], false, null, null,
true, false, [null, "tstatic"], false, null, null,
], ],
[["", "->tmethod"], [["", "->tmethod"],
false, null, null, false, null, null,
false, null, null, false, null, null,
], ],
[["", "::tmissing"], [["", "::tmissing"],
true, false, [null, "tmissing"], false, null, null,
true, false, [null, "tmissing"], false, null, null,
], ],
[["", "->tmissing"], [["", "->tmissing"],
false, null, null, false, null, null,
false, null, null, false, null, null,
], ],
[[MyClass::class, "tstatic"], [["xxx", "tmissing"],
true, true, [MyClass::class, "tstatic"], false, null, null,
true, true, [MyClass::class, "tstatic"], true, true, ["xxx", "tmissing"],
], ],
[[MyClass::class, "::tstatic"], [["xxx", "::tmissing"],
true, true, [MyClass::class, "tstatic"], false, null, null,
true, true, [MyClass::class, "tstatic"], true, true, ["xxx", "tmissing"],
], ],
[[MyClass::class, "tmethod"], [["xxx", "->tmissing"],
true, true, [MyClass::class, "tmethod"],
true, true, [MyClass::class, "tmethod"],
],
[[MyClass::class, "->tmethod"],
false, null, null, false, null, null,
false, null, null, false, null, null,
], ],
[[MyClass::class, "tmissing"], [[SC::class, "tstatic"],
false, null, null, true, true, [SC::class, "tstatic"],
true, true, [MyClass::class, "tmissing"], true, true, [SC::class, "tstatic"],
], ],
[[MyClass::class, "::tmissing"], [[SC::class, "::tstatic"],
false, null, null, true, true, [SC::class, "tstatic"],
true, true, [MyClass::class, "tmissing"], true, true, [SC::class, "tstatic"],
], ],
[[MyClass::class, "->tmissing"], [[SC::class, "tmethod"],
true, true, [SC::class, "tmethod"],
true, true, [SC::class, "tmethod"],
],
[[SC::class, "->tmethod"],
false, null, null,
false, null, null,
],
[[SC::class, "tmissing"],
false, null, null,
true, true, [SC::class, "tmissing"],
],
[[SC::class, "::tmissing"],
false, null, null,
true, true, [SC::class, "tmissing"],
],
[[SC::class, "->tmissing"],
false, null, null, false, null, null,
false, null, null, false, null, null,
], ],
@ -534,6 +593,9 @@ namespace nur\sery\wip\php {
$verifix1, $bound1, $func1, $verifix1, $bound1, $func1,
$verifix2, $bound2, $func2, $verifix2, $bound2, $func2,
] = $args; ] = $args;
if ($func === ["", "tsimple"]) {
//echo "breakpoint";
}
$workf = $func; $workf = $func;
$msg = var_export($func, true)." (strict)"; $msg = var_export($func, true)." (strict)";
@ -603,21 +665,29 @@ namespace nur\sery\wip\php {
true, false, [null, "tmissing"], true, false, [null, "tmissing"],
true, false, [null, "tmissing"], true, false, [null, "tmissing"],
], ],
[MyClass::class."::tstatic", ["xxx::tmissing",
false, null, null, false, null, null,
false, null, null, false, null, null,
], ],
[MyClass::class."->tmethod", ["xxx->tmissing",
true, true, [MyClass::class, "tmethod"], false, null, null,
true, true, [MyClass::class, "tmethod"], true, true, ["xxx", "tmissing"],
], ],
[MyClass::class."::tmissing", [SC::class."::tstatic",
false, null, null, false, null, null,
false, null, null, false, null, null,
], ],
[MyClass::class."->tmissing", [SC::class."->tmethod",
true, true, [SC::class, "tmethod"],
true, true, [SC::class, "tmethod"],
],
[SC::class."::tmissing",
false, null, null, false, null, null,
true, true, [MyClass::class, "tmissing"], false, null, null,
],
[SC::class."->tmissing",
false, null, null,
true, true, [SC::class, "tmissing"],
], ],
# tableaux avec un seul scalaire # tableaux avec un seul scalaire
[[], [[],
@ -668,21 +738,29 @@ namespace nur\sery\wip\php {
true, false, [null, "tmissing"], true, false, [null, "tmissing"],
true, false, [null, "tmissing"], true, false, [null, "tmissing"],
], ],
[[MyClass::class."::tstatic"], [["xxx::tmissing"],
false, null, null, false, null, null,
false, null, null, false, null, null,
], ],
[[MyClass::class."->tmethod"], [["xxx->tmissing"],
true, true, [MyClass::class, "tmethod"], false, null, null,
true, true, [MyClass::class, "tmethod"], true, true, ["xxx", "tmissing"],
], ],
[[MyClass::class."::tmissing"], [[SC::class."::tstatic"],
false, null, null, false, null, null,
false, null, null, false, null, null,
], ],
[[MyClass::class."->tmissing"], [[SC::class."->tmethod"],
true, true, [SC::class, "tmethod"],
true, true, [SC::class, "tmethod"],
],
[[SC::class."::tmissing"],
false, null, null, false, null, null,
true, true, [MyClass::class, "tmissing"], false, null, null,
],
[[SC::class."->tmissing"],
false, null, null,
true, true, [SC::class, "tmissing"],
], ],
# tableaux avec deux scalaires # tableaux avec deux scalaires
[[null, "tsimple"], [[null, "tsimple"],
@ -742,60 +820,72 @@ namespace nur\sery\wip\php {
false, null, null, false, null, null,
], ],
[["", "tsimple"], [["", "tsimple"],
true, false, [null, "tsimple"], false, null, null,
true, false, [null, "tsimple"], false, null, null,
], ],
[["", 'nur\sery\wip\php\impl\ntsimple'], [["", 'nur\sery\wip\php\impl\ntsimple'],
false, null, null, false, null, null,
false, null, null, false, null, null,
], ],
[["", "tmissing"], [["", "tmissing"],
true, false, [null, "tmissing"], false, null, null,
true, false, [null, "tmissing"], false, null, null,
], ],
[["", "::tstatic"], [["", "::tstatic"],
false, null, null, false, null, null,
false, null, null, false, null, null,
], ],
[["", "->tmethod"], [["", "->tmethod"],
true, false, [null, "tmethod"], false, null, null,
true, false, [null, "tmethod"], false, null, null,
], ],
[["", "::tmissing"], [["", "::tmissing"],
false, null, null, false, null, null,
false, null, null, false, null, null,
], ],
[["", "->tmissing"], [["", "->tmissing"],
true, false, [null, "tmissing"],
true, false, [null, "tmissing"],
],
[[MyClass::class, "tstatic"],
true, true, [MyClass::class, "tstatic"],
true, true, [MyClass::class, "tstatic"],
],
[[MyClass::class, "::tstatic"],
false, null, null, false, null, null,
false, null, null, false, null, null,
], ],
[[MyClass::class, "tmethod"], [["xxx", "tmissing"],
true, true, [MyClass::class, "tmethod"],
true, true, [MyClass::class, "tmethod"],
],
[[MyClass::class, "->tmethod"],
true, true, [MyClass::class, "tmethod"],
true, true, [MyClass::class, "tmethod"],
],
[[MyClass::class, "tmissing"],
false, null, null, false, null, null,
true, true, [MyClass::class, "tmissing"], true, true, ["xxx", "tmissing"],
], ],
[[MyClass::class, "::tmissing"], [["xxx", "::tmissing"],
false, null, null, false, null, null,
false, null, null, false, null, null,
], ],
[[MyClass::class, "->tmissing"], [["xxx", "->tmissing"],
false, null, null, false, null, null,
true, true, [MyClass::class, "tmissing"], true, true, ["xxx", "tmissing"],
],
[[SC::class, "tstatic"],
true, true, [SC::class, "tstatic"],
true, true, [SC::class, "tstatic"],
],
[[SC::class, "::tstatic"],
false, null, null,
false, null, null,
],
[[SC::class, "tmethod"],
true, true, [SC::class, "tmethod"],
true, true, [SC::class, "tmethod"],
],
[[SC::class, "->tmethod"],
true, true, [SC::class, "tmethod"],
true, true, [SC::class, "tmethod"],
],
[[SC::class, "tmissing"],
false, null, null,
true, true, [SC::class, "tmissing"],
],
[[SC::class, "::tmissing"],
false, null, null,
false, null, null,
],
[[SC::class, "->tmissing"],
false, null, null,
true, true, [SC::class, "tmissing"],
], ],
]; ];

15
tests/wip/php/impl/CC.php Normal file
View File

@ -0,0 +1,15 @@
<?php
namespace nur\sery\wip\php\impl;
class CC {
function __construct() {
}
static function tstatic(): int {
return 10;
}
function tmethod(): int {
return 11;
}
}

View File

@ -1,12 +1,12 @@
<?php <?php
namespace nur\sery\wip\php\impl; namespace nur\sery\wip\php\impl;
class MyClass { class SC {
static function tstatic(): int { static function tstatic(): int {
return 1; return 10;
} }
function tmethod(): int { function tmethod(): int {
return 2; return 11;
} }
} }

View File

@ -2,7 +2,6 @@
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\StateException;
use nur\sery\ValueException; use nur\sery\ValueException;
@ -13,66 +12,24 @@ use ReflectionMethod;
/** /**
* Class func: outils pour appeler fonctions et méthodes dynamiquement * Class func: outils pour appeler fonctions et méthodes dynamiquement
* *
* les fonctions supportées sont: * les types de fonctions supportés sont:
* - fonctions simples (globales ou dans un namespace) * - fonctions simples (globales ou dans un namespace)
* - fonctions statiques * - classes (l'appel de cette "fonction" provoque l'instanciation de la classe)
* - méthodes * - méthodes statiques (liées à une classe)
* - méthodes non statiques (liées à un objet)
* - Closure * - 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 * 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 * classe ou à un objet) ou non liées (il faut les lier avant de pouvoir les
* utiliser) * utiliser)
*/ */
class func { class func {
/** private static function _is_invalid(?string $f): bool {
* vérifier que $func est une fonction simple et la normaliser le cas échéant. return $f === null || $f === "" || $f === "::" || $f === "->";
* 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_nfunction(?string $f): bool {
* vérifier que $func est une fonction simple avec les règles de return strpos($f, "\\") !== false;
* {@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 === "->";
}
private static function _is_nfunction(?string $m): bool {
return strpos($m, "\\") !== false;
} }
private static function _parse_static(?string &$m): bool { private static function _parse_static(?string &$m): bool {
@ -89,6 +46,116 @@ class func {
return true; return true;
} }
#############################################################################
# Fonctions
/**
* 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_function(&$func, bool $strict=true, ?string &$reason=null): bool {
if ($strict) {
$msg = var_export($func, true);
$reason = null;
}
if ($func instanceof ReflectionFunction) return true;
if (is_string($func)) {
$func = [false, $func];
} elseif (is_array($func)) {
if (!array_key_exists(0, $func)) return false;
if (!array_key_exists(1, $func)) return false;
} else {
return false;
}
if ($func[0] !== false) return false;
$f = $func[1];
if (!is_string($f)) return false;
if (self::_is_invalid($f)) return false;
if (self::_parse_static($f)) return false;
if (self::_parse_method($f)) return false;
if ($strict) {
$reason = null;
if (class_exists($f)) {
$reason = "$msg: is a class";
return false;
}
if (!function_exists($f)) {
$reason = "$msg: function not found";
return false;
}
}
return true;
}
/**
* vérifier que $func est une fonction simple avec les règles de
* {@link self::verifix_function()}
*/
static function is_function($func, bool $strict=true, ?string &$reason=null): bool {
return self::verifix_function($func, $strict, $reason);
}
#############################################################################
# Classes
/**
* vérifier que $func est une classe et la normaliser le cas échéant.
* retourner true si c'est une classe, false sinon
*
* les formes suivantes sont supportées:
* - "class"
* - ["class", false, ...$args] c'est la forme normalisée
*
* @param bool $strict vérifier l'existence de la classe (ne pas uniquement
* faire une vérification syntaxique)
*/
static function verifix_class(&$func, bool $strict=true, ?string &$reason=null): bool {
if ($strict) {
$msg = var_export($func, true);
$reason = null;
}
if ($func instanceof ReflectionClass) return true;
if (is_string($func)) {
$func = [$func, false];
} elseif (is_array($func)) {
if (!array_key_exists(0, $func)) return false;
if (!array_key_exists(1, $func)) return false;
} else {
return false;
}
$c = $func[0];
if (!is_string($c)) return false;
if (self::_is_invalid($c)) return false;
if (self::_parse_static($f)) return false;
if (self::_parse_method($f)) return false;
if ($func[1] !== false) return false;
if ($strict) {
if (!class_exists($c)) {
$reason = "$msg: class not found";
return false;
}
}
return true;
}
/**
* vérifier que $func est une classe avec les règles de
* {@link self::verifix_class()}
*/
static function is_class($func, bool $strict=true, ?string &$reason=null): bool {
return self::verifix_class($func, $strict, $reason);
}
#############################################################################
# Méthodes statiques
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, "::");
@ -136,7 +203,15 @@ class func {
* @param bool $strict vérifier l'existence de la classe et de la méthode si * @param bool $strict vérifier l'existence de la classe et de la méthode si
* la méthode est liée (ne pas uniquement faire une vérification syntaxique) * la méthode est liée (ne pas uniquement faire une vérification syntaxique)
*/ */
static function verifix_static(&$func, bool $strict=true, ?bool &$bound=null): bool { static function verifix_static(&$func, bool $strict=true, ?bool &$bound=null, ?string &$reason=null): bool {
if ($strict) {
$msg = var_export($func, true);
$reason = null;
}
if ($func instanceof ReflectionMethod) {
$bound = false;
return true;
}
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];
@ -144,21 +219,27 @@ class 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 (is_object($c)) $c = get_class($c);
$func[0] = $c; if (is_string($c)) {
if ($f !== null) { if (self::_is_invalid($c)) return false;
# ["class::method"] --> ["class", "method"] if (self::_parse_class_s($c, $c, $f)) {
array_splice($func, 1, 0, [$f]); $func[0] = $c;
if ($f !== null) {
# ["class::method"] --> ["class", "method"]
array_splice($func, 1, 0, [$f]);
}
$bound = true;
} elseif (self::_parse_c_static($c, $c, $f, $bound)) {
# ["::method"] --> [null, "method"]
array_splice($func, 0, 0, [null]);
$func[1] = $f;
} else {
$func[0] = $c;
$bound = is_string($c);
} }
$bound = true;
} elseif (self::_parse_c_static($c, $c, $f, $bound)) {
# ["::method"] --> [null, "method"]
array_splice($func, 0, 0, [null]);
$func[1] = $f;
} else { } else {
if (self::_is_invalid($c)) $c = null; $func[0] = null;
$func[0] = $c; $bound = false;
$bound = is_string($c);
} }
# #
if (!array_key_exists(1, $func)) return false; if (!array_key_exists(1, $func)) return false;
@ -169,19 +250,31 @@ class func {
$c = $rc; $c = $rc;
$bound = $rbound; $bound = $rbound;
} }
} elseif (self::_is_invalid($f)) { } else {
return false; if (self::_is_invalid($f)) return false;
} elseif (self::_is_nfunction($f)) { if (self::_is_nfunction($f)) return false;
return false; if (self::_parse_method($f)) return false;
} elseif (self::_parse_method($f)) { self::_parse_static($f);
return false;
} elseif (self::_parse_static($f)) {
} }
$func[1] = $f; $func[1] = $f;
} else { } else {
return false; return false;
} }
if ($strict && $bound && !method_exists($c, $f)) return false; if ($strict) {
$reason = null;
if ($bound) {
if (!class_exists($c)) {
$reason = "$msg: class not found";
return false;
}
if (!method_exists($c, $f)) {
$reason = "$msg: method not found";
return false;
}
} else {
$reason = "$msg: not bound";
}
}
return true; return true;
} }
@ -189,10 +282,13 @@ class func {
* vérifier que $func est une méthode statique avec les règles de * vérifier que $func est une méthode statique avec les règles de
* {@link self::verifix_static()} * {@link self::verifix_static()}
*/ */
static function is_static($func, bool $strict=true, ?bool &$bound=null): bool { static function is_static($func, bool $strict=true, ?bool &$bound=null, ?string &$reason=null): bool {
return self::verifix_static($func, $strict, $bound); return self::verifix_static($func, $strict, $bound, $reason);
} }
#############################################################################
# Méthodes non statiques
private static function _parse_class_m(?string $cm, ?string &$c, ?string &$m): bool { private static function _parse_class_m(?string $cm, ?string &$c, ?string &$m): 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, "->");
@ -240,7 +336,15 @@ class func {
* @param bool $strict vérifier l'existence de la classe et de la méthode si * @param bool $strict vérifier l'existence de la classe et de la méthode si
* la méthode est liée (ne pas uniquement faire une vérification syntaxique) * la méthode est liée (ne pas uniquement faire une vérification syntaxique)
*/ */
static function verifix_method(&$func, bool $strict=true, ?bool &$bound=null): bool { static function verifix_method(&$func, bool $strict=true, ?bool &$bound=null, ?string &$reason=null): bool {
if ($strict) {
$msg = var_export($func, true);
$reason = null;
}
if ($func instanceof ReflectionMethod) {
$bound = false;
return true;
}
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];
@ -248,21 +352,28 @@ class 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 (is_object($c)) {
$func[0] = $c;
if ($f !== null) {
# ["class->method"] --> ["class", "method"]
array_splice($func, 1, 0, [$f]);
}
$bound = true; $bound = true;
} elseif (self::_parse_c_method($c, $c, $f, $bound)) { } elseif (is_string($c)) {
# ["->method"] --> [null, "method"] if (self::_is_invalid($c)) return false;
array_splice($func, 0, 0, [null]); if (self::_parse_class_m($c, $c, $f)) {
$func[1] = $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 {
$func[0] = $c;
$bound = is_string($c);
}
} else { } else {
if (self::_is_invalid($c)) $c = null; $func[0] = null;
$func[0] = $c; $bound = false;
$bound = is_string($c);
} }
# #
if (!array_key_exists(1, $func)) return false; if (!array_key_exists(1, $func)) return false;
@ -273,19 +384,31 @@ class func {
$c = $rc; $c = $rc;
$bound = $rbound; $bound = $rbound;
} }
} elseif (self::_is_invalid($f)) { } else {
return false; if (self::_is_invalid($f)) return false;
} elseif (self::_is_nfunction($f)) { if (self::_is_nfunction($f)) return false;
return false; if (self::_parse_static($f)) return false;
} elseif (self::_parse_static($f)) { self::_parse_method($f);
return false;
} elseif (self::_parse_method($f)) {
} }
$func[1] = $f; $func[1] = $f;
} else { } else {
return false; return false;
} }
if ($strict && $bound && !method_exists($c, $f)) return false; if ($strict) {
$reason = null;
if ($bound) {
if (!is_object($c) && !class_exists($c)) {
$reason = "$msg: class not found";
return false;
}
if (!method_exists($c, $f)) {
$reason = "$msg: method not found";
return false;
}
} else {
$reason = "$msg: not bound";
}
}
return true; return true;
} }
@ -293,37 +416,30 @@ class func {
* vérifier que $func est une méthode non statique avec les règles de * vérifier que $func est une méthode non statique avec les règles de
* {@link self::verifix_method()} * {@link self::verifix_method()}
*/ */
static function is_method($func, bool $strict=true, ?bool &$bound=null): bool { static function is_method($func, bool $strict=true, ?bool &$bound=null, ?string &$reason=null): bool {
return self::verifix_method($func, $strict, $bound); return self::verifix_method($func, $strict, $bound, $reason);
}
static function verifix_cons(&$func, bool $strict=true): bool {
if (is_string($func)) {
} elseif (is_array($func)) {
} else {
return false;
}
return false;#XXX
} }
#############################################################################
# func
static function with($func, bool $strict=true): self { static function with($func, bool $strict=true): self {
if ($func instanceof Closure) { if ($func instanceof Closure) {
return new self($func); return new self($func);
} elseif (self::verifix_simple($func, $strict)) { } elseif (self::verifix_function($func, $strict, $reason)) {
return new self($func); return new self($func);
} elseif (self::verifix_cons($func, $strict)) { } elseif (self::verifix_class($func, $strict, $reason)) {
return new self($func); return new self($func);
} else { } elseif (self::verifix_static($func, $strict, $bound, $reason)) {
if (self::verifix_static($func, $strict, $bound)) { return new self($func);
} elseif (self::verifix_method($func, $strict, $bound)) { } elseif (self::verifix_method($func, $strict, $bound, $reason)) {
} else {
throw ValueException::invalid_type($func, "callable");
}
if (!$bound) throw ValueException::invalid_value($func, null, "is not bound");
return new self($func); return new self($func);
} }
if ($reason === null) {
$msg = var_export($func, true);
$reason = "$msg: not a callable";
}
throw new ValueException($reason);
} }
static function call($func, ...$args) { static function call($func, ...$args) {
@ -333,40 +449,57 @@ class func {
static function with_object($func, object $object, bool $rebind=false, bool $strict=true): self { static function with_object($func, object $object, bool $rebind=false, bool $strict=true): self {
if ($func instanceof Closure) { if ($func instanceof Closure) {
return new self($func); return new self($func);
} elseif (self::verifix_simple($func, $strict)) { } elseif (self::verifix_function($func, $strict, $reason)) {
return new self($func); return new self($func);
} elseif (self::verifix_cons($func, $strict)) { } elseif (self::verifix_class($func, $strict, $reason)) {
return new self($func); return new self($func);
} else { } elseif (self::verifix_method($func, $strict, $bound, $reason)) {
if (self::verifix_method($func, $strict, $bound)) { if (!$bound || $rebind) $func[0] = $object;
} elseif (self::verifix_static($func, $strict, $bound)) { return new self($func);
} else { } elseif (self::verifix_static($func, $strict, $bound, $reason)) {
throw ValueException::invalid_type($func, "callable");
}
if (!$bound || $rebind) $func[0] = $object; if (!$bound || $rebind) $func[0] = $object;
return new self($func); return new self($func);
} }
if ($reason === null) {
$msg = var_export($func, true);
$reason = "$msg: not a callable";
}
throw new ValueException($reason);
}
static function call_object($func, $object, ...$args) {
return self::with_object($func, $object)->invoke($args);
} }
static function with_class($func, $class, bool $rebind=false, bool $strict=true): self { static function with_class($func, $class, bool $rebind=false, bool $strict=true): self {
if ($func instanceof Closure) { if ($func instanceof Closure) {
return new self($func); return new self($func);
} elseif (self::verifix_simple($func, $strict)) { } elseif (self::verifix_function($func, $strict, $reason)) {
return new self($func); return new self($func);
} elseif (self::verifix_cons($func, $strict)) { } elseif (self::verifix_class($func, $strict, $reason)) {
return new self($func); return new self($func);
} else { } elseif (self::verifix_method($func, $strict, $bound, $reason)) {
if (self::verifix_method($func, $strict, $bound)) { if (!$bound || $rebind) {
} elseif (self::verifix_static($func, $strict, $bound)) { if (is_object($class)) $class = get_class($class);
} else { $func[0] = $class;
throw ValueException::invalid_type($func, "callable");
} }
return new self($func);
} elseif (self::verifix_static($func, $strict, $bound, $reason)) {
if (!$bound || $rebind) { if (!$bound || $rebind) {
if (is_object($class)) $class = get_class($class); if (is_object($class)) $class = get_class($class);
$func[0] = $class; $func[0] = $class;
} }
return new self($func); return new self($func);
} }
if ($reason === null) {
$msg = var_export($func, true);
$reason = "$msg: not a callable";
}
throw new ValueException($reason);
}
static function call_class($func, $class, ...$args) {
return self::with_class($func, $class)->invoke($args);
} }
############################################################################# #############################################################################
@ -378,8 +511,8 @@ class func {
$prefixArgs = []; $prefixArgs = [];
if ($func instanceof Closure) { if ($func instanceof Closure) {
$type = self::TYPE_CLOSURE; $type = self::TYPE_CLOSURE;
$reflection = new ReflectionFunction($func);
$object = $func; $object = $func;
$reflection = new ReflectionFunction($func);
} elseif ($func instanceof ReflectionFunction) { } elseif ($func instanceof ReflectionFunction) {
$type = self::TYPE_SIMPLE; $type = self::TYPE_SIMPLE;
$reflection = $func; $reflection = $func;