", false, null, false, null, ], ["tsimple", true, [false, "tsimple"], true, [false, "tsimple"], ], ['nur\sery\php\impl\ntsimple', true, [false, 'nur\sery\php\impl\ntsimple'], true, [false, 'nur\sery\php\impl\ntsimple'], ], ['tmissing', false, null, true, [false, 'tmissing'], ], ["::tstatic", false, null, false, null, ], ["->tmethod", false, null, false, null, ], ["::tmissing", false, null, false, null, ], ["->tmissing", false, null, false, null, ], ["xxx::tmissing", false, null, false, null, ], ["xxx->tmissing", false, null, false, null, ], [SC::class."::tstatic", false, null, false, null, ], [SC::class."->tmethod", false, null, false, null, ], [SC::class."::tmissing", false, null, false, null, ], [SC::class."->tmissing", false, null, false, null, ], # tableaux avec un seul scalaire [[], false, null, false, null, ], [[null], false, null, false, null, ], [[false], false, null, false, null, ], [[""], false, null, false, null, ], [["::"], false, null, false, null, ], [["->"], false, null, false, null, ], [["tsimple"], false, null, false, null, ], [['nur\sery\php\impl\ntsimple'], false, null, false, null, ], [["::tstatic"], false, null, false, null, ], [["->tmethod"], false, null, false, null, ], [["::tmissing"], false, null, false, null, ], [["->tmissing"], false, null, false, null, ], [["xxx::tmissing"], false, null, false, null, ], [["xxx->tmissing"], false, null, false, null, ], [[SC::class."::tstatic"], false, null, false, null, ], [[SC::class."->tmethod"], false, null, false, null, ], [[SC::class."::tmissing"], false, null, false, null, ], [[SC::class."->tmissing"], false, null, false, null, ], # tableaux avec deux scalaires [[null, "tsimple"], false, null, false, null, ], [[null, 'nur\sery\php\impl\ntsimple'], false, null, false, null, ], [[null, "tmissing"], false, null, false, null, ], [[null, "::tstatic"], false, null, false, null, ], [[null, "->tmethod"], false, null, false, null, ], [[null, "::tmissing"], false, null, false, null, ], [[null, "->tmissing"], false, null, false, null, ], [[false, "tsimple"], true, [false, "tsimple"], true, [false, "tsimple"], ], [[false, 'nur\sery\php\impl\ntsimple'], true, [false, 'nur\sery\php\impl\ntsimple'], true, [false, 'nur\sery\php\impl\ntsimple'], ], [[false, "tmissing"], false, null, true, [false, "tmissing"], ], [[false, "::tstatic"], false, null, false, null, ], [[false, "->tmethod"], false, null, false, null, ], [[false, "::tmissing"], false, null, false, null, ], [[false, "->tmissing"], false, null, false, null, ], [["", "tsimple"], false, null, false, null, ], [["", 'nur\sery\php\impl\ntsimple'], false, null, false, null, ], [["", "tmissing"], false, null, false, null, ], [["", "::tstatic"], false, null, false, null, ], [["", "->tmethod"], false, null, false, null, ], [["", "::tmissing"], false, null, false, null, ], [["", "->tmissing"], false, null, false, null, ], [["xxx", "tmissing"], false, null, false, null, ], [["xxx", "::tmissing"], false, null, false, null, ], [["xxx", "->tmissing"], false, null, false, null, ], [[SC::class, "tstatic"], false, null, false, null, ], [[SC::class, "::tstatic"], false, null, false, null, ], [[SC::class, "tmethod"], false, null, false, null, ], [[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, ], ]; function testFunction() { foreach (self::FUNCTION_TESTS as $args) { [$func, $verifix1, $func1, $verifix2, $func2, ] = $args; if ($func === ["", "tsimple"]) { //echo "breakpoint"; } $workf = $func; $msg = var_export($func, true)." (strict)"; self::assertSame($verifix1, func::verifix_function($workf, true), "$msg --> verifix"); if ($verifix1) { self::assertSame($func1, $workf, "$msg --> func"); } $workf = $func; $msg = var_export($func, true)." (lenient)"; self::assertSame($verifix2, func::verifix_function($workf, false), "$msg --> verifix"); if ($verifix2) { self::assertSame($func2, $workf, "$msg --> func"); } } } const STATIC_TESTS = [ # scalaires [null, false, null, null, false, null, null, ], [false, false, null, null, false, null, null, ], ["", false, null, null, false, null, null, ], ["::", false, null, null, false, null, null, ], ["->", false, null, null, false, null, null, ], ["tsimple", false, null, null, false, null, null, ], ['nur\sery\php\impl\ntsimple', false, null, null, false, null, null, ], ['tmissing', false, null, null, false, null, null, ], ["::tstatic", true, false, [null, "tstatic"], true, false, [null, "tstatic"], ], ["->tmethod", false, null, null, false, null, null, ], ["::tmissing", true, false, [null, "tmissing"], true, false, [null, "tmissing"], ], ["->tmissing", false, null, null, false, null, null, ], ["xxx::tmissing", false, null, null, true, true, ["xxx", "tmissing"], ], ["xxx->tmissing", false, null, null, false, null, null, ], [SC::class."::tstatic", true, true, [SC::class, "tstatic"], true, true, [SC::class, "tstatic"], ], [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, ], # tableaux avec un seul scalaire [[], false, null, null, false, null, null, ], [[null], false, null, null, false, null, null, ], [[false], false, null, null, false, null, null, ], [[""], false, null, null, false, null, null, ], [["::"], false, null, null, false, null, null, ], [["->"], false, null, null, false, null, null, ], [["tsimple"], false, null, null, false, null, null, ], [['nur\sery\php\impl\ntsimple'], false, null, null, false, null, null, ], [["::tstatic"], true, false, [null, "tstatic"], true, false, [null, "tstatic"], ], [["->tmethod"], false, null, null, false, null, null, ], [["::tmissing"], true, false, [null, "tmissing"], true, false, [null, "tmissing"], ], [["->tmissing"], false, null, null, false, null, null, ], [["xxx::tmissing"], false, null, null, true, true, ["xxx", "tmissing"], ], [["xxx->tmissing"], false, null, null, false, null, null, ], [[SC::class."::tstatic"], true, true, [SC::class, "tstatic"], true, true, [SC::class, "tstatic"], ], [[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, ], # tableaux avec deux scalaires [[null, "tsimple"], true, false, [null, "tsimple"], true, false, [null, "tsimple"], ], [[null, 'nur\sery\php\impl\ntsimple'], false, null, null, false, null, null, ], [[null, "tmissing"], true, false, [null, "tmissing"], true, false, [null, "tmissing"], ], [[null, "::tstatic"], true, false, [null, "tstatic"], true, false, [null, "tstatic"], ], [[null, "->tmethod"], false, null, null, false, null, null, ], [[null, "::tmissing"], true, false, [null, "tmissing"], true, false, [null, "tmissing"], ], [[null, "->tmissing"], false, null, null, false, null, null, ], [[false, "tsimple"], false, null, null, false, null, null, ], [[false, 'nur\sery\php\impl\ntsimple'], false, null, null, false, null, null, ], [[false, "tmissing"], false, null, null, false, null, null, ], [[false, "::tstatic"], false, null, null, false, null, null, ], [[false, "->tmethod"], false, null, null, false, null, null, ], [[false, "::tmissing"], false, null, null, false, null, null, ], [[false, "->tmissing"], false, null, null, false, null, null, ], [["", "tsimple"], false, null, null, false, null, null, ], [["", 'nur\sery\php\impl\ntsimple'], false, null, null, false, null, null, ], [["", "tmissing"], false, null, null, false, null, null, ], [["", "::tstatic"], false, null, null, false, null, null, ], [["", "->tmethod"], false, null, null, false, null, null, ], [["", "::tmissing"], false, null, null, false, null, null, ], [["", "->tmissing"], false, null, null, false, null, null, ], [["xxx", "tmissing"], false, null, null, true, true, ["xxx", "tmissing"], ], [["xxx", "::tmissing"], false, null, null, true, true, ["xxx", "tmissing"], ], [["xxx", "->tmissing"], false, null, null, false, null, null, ], [[SC::class, "tstatic"], true, true, [SC::class, "tstatic"], true, true, [SC::class, "tstatic"], ], [[SC::class, "::tstatic"], true, true, [SC::class, "tstatic"], true, true, [SC::class, "tstatic"], ], [[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, ], ]; function testStatic() { foreach (self::STATIC_TESTS as $args) { [$func, $verifix1, $bound1, $func1, $verifix2, $bound2, $func2, ] = $args; if ($func === ["", "tsimple"]) { //echo "breakpoint"; } $workf = $func; $msg = var_export($func, true)." (strict)"; self::assertSame($verifix1, func::verifix_static($workf, true, $bound), "$msg --> verifix"); if ($verifix1) { self::assertSame($bound1, $bound, "$msg --> bound"); self::assertSame($func1, $workf, "$msg --> func"); } $workf = $func; $msg = var_export($func, true)." (lenient)"; self::assertSame($verifix2, func::verifix_static($workf, false, $bound), "$msg --> verifix"); if ($verifix2) { self::assertSame($bound2, $bound, "$msg --> bound"); self::assertSame($func2, $workf, "$msg --> func"); } } } const METHOD_TESTS = [ # scalaires [null, false, null, null, false, null, null, ], [false, false, null, null, false, null, null, ], ["", false, null, null, false, null, null, ], ["::", false, null, null, false, null, null, ], ["->", false, null, null, false, null, null, ], ["tsimple", false, null, null, false, null, null, ], ['nur\sery\php\impl\ntsimple', false, null, null, false, null, null, ], ['tmissing', false, null, null, false, null, null, ], ["::tstatic", false, null, null, false, null, null, ], ["->tmethod", true, false, [null, "tmethod"], true, false, [null, "tmethod"], ], ["::tmissing", false, null, null, false, null, null, ], ["->tmissing", true, false, [null, "tmissing"], true, false, [null, "tmissing"], ], ["xxx::tmissing", false, null, null, false, null, null, ], ["xxx->tmissing", false, null, null, true, true, ["xxx", "tmissing"], ], [SC::class."::tstatic", false, null, null, false, null, null, ], [SC::class."->tmethod", true, true, [SC::class, "tmethod"], true, true, [SC::class, "tmethod"], ], [SC::class."::tmissing", false, null, null, false, null, null, ], [SC::class."->tmissing", false, null, null, true, true, [SC::class, "tmissing"], ], # tableaux avec un seul scalaire [[], false, null, null, false, null, null, ], [[null], false, null, null, false, null, null, ], [[false], false, null, null, false, null, null, ], [[""], false, null, null, false, null, null, ], [["::"], false, null, null, false, null, null, ], [["->"], false, null, null, false, null, null, ], [["tsimple"], false, null, null, false, null, null, ], [['nur\sery\php\impl\ntsimple'], false, null, null, false, null, null, ], [["::tstatic"], false, null, null, false, null, null, ], [["->tmethod"], true, false, [null, "tmethod"], true, false, [null, "tmethod"], ], [["::tmissing"], false, null, null, false, null, null, ], [["->tmissing"], true, false, [null, "tmissing"], true, false, [null, "tmissing"], ], [["xxx::tmissing"], false, null, null, false, null, null, ], [["xxx->tmissing"], false, null, null, true, true, ["xxx", "tmissing"], ], [[SC::class."::tstatic"], false, null, null, false, null, null, ], [[SC::class."->tmethod"], true, true, [SC::class, "tmethod"], true, true, [SC::class, "tmethod"], ], [[SC::class."::tmissing"], false, null, null, false, null, null, ], [[SC::class."->tmissing"], false, null, null, true, true, [SC::class, "tmissing"], ], # tableaux avec deux scalaires [[null, "tsimple"], true, false, [null, "tsimple"], true, false, [null, "tsimple"], ], [[null, 'nur\sery\php\impl\ntsimple'], false, null, null, false, null, null, ], [[null, "tmissing"], true, false, [null, "tmissing"], true, false, [null, "tmissing"], ], [[null, "::tstatic"], false, null, null, false, null, null, ], [[null, "->tmethod"], true, false, [null, "tmethod"], true, false, [null, "tmethod"], ], [[null, "::tmissing"], false, null, null, false, null, null, ], [[null, "->tmissing"], true, false, [null, "tmissing"], true, false, [null, "tmissing"], ], [[false, "tsimple"], false, null, null, false, null, null, ], [[false, 'nur\sery\php\impl\ntsimple'], false, null, null, false, null, null, ], [[false, "tmissing"], false, null, null, false, null, null, ], [[false, "::tstatic"], false, null, null, false, null, null, ], [[false, "->tmethod"], false, null, null, false, null, null, ], [[false, "::tmissing"], false, null, null, false, null, null, ], [[false, "->tmissing"], false, null, null, false, null, null, ], [["", "tsimple"], false, null, null, false, null, null, ], [["", 'nur\sery\php\impl\ntsimple'], false, null, null, false, null, null, ], [["", "tmissing"], false, null, null, false, null, null, ], [["", "::tstatic"], false, null, null, false, null, null, ], [["", "->tmethod"], false, null, null, false, null, null, ], [["", "::tmissing"], false, null, null, false, null, null, ], [["", "->tmissing"], false, null, null, false, null, null, ], [["xxx", "tmissing"], false, null, null, true, true, ["xxx", "tmissing"], ], [["xxx", "::tmissing"], false, null, null, false, null, null, ], [["xxx", "->tmissing"], false, null, null, 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"], ], ]; function testMethod() { foreach (self::METHOD_TESTS as $args) { [$func, $verifix1, $bound1, $func1, $verifix2, $bound2, $func2, ] = $args; $workf = $func; $msg = var_export($func, true)." (strict)"; self::assertSame($verifix1, func::verifix_method($workf, true, $bound), "$msg --> verifix"); if ($verifix1) { self::assertSame($bound1, $bound, "$msg --> bound"); self::assertSame($func1, $workf, "$msg --> func"); } $workf = $func; $msg = var_export($func, true)." (lenient)"; self::assertSame($verifix2, func::verifix_method($workf, false, $bound), "$msg --> verifix"); if ($verifix2) { self::assertSame($bound2, $bound, "$msg --> bound"); self::assertSame($func2, $workf, "$msg --> func"); } } } function testInvokeFunction() { # m1 self::assertSame([null], func::call("tm1")); self::assertSame([null], func::call("tm1", null)); self::assertSame([null], func::call("tm1", null, null)); self::assertSame([null], func::call("tm1", null, null, null)); self::assertSame([null], func::call("tm1", null, null, null, null)); self::assertSame([1], func::call("tm1", 1)); self::assertSame([1], func::call("tm1", 1, 2)); self::assertSame([1], func::call("tm1", 1, 2, 3)); self::assertSame([1], func::call("tm1", 1, 2, 3, 4)); # o1 self::assertSame([9], func::call("to1")); self::assertSame([null], func::call("to1", null)); self::assertSame([null], func::call("to1", null, null)); self::assertSame([null], func::call("to1", null, null, null)); self::assertSame([null], func::call("to1", null, null, null, null)); self::assertSame([1], func::call("to1", 1)); self::assertSame([1], func::call("to1", 1, 2)); self::assertSame([1], func::call("to1", 1, 2, 3)); self::assertSame([1], func::call("to1", 1, 2, 3, 4)); # v self::assertSame([], func::call("tv")); self::assertSame([null], func::call("tv", null)); self::assertSame([null, null], func::call("tv", null, null)); self::assertSame([null, null, null], func::call("tv", null, null, null)); self::assertSame([null, null, null, null], func::call("tv", null, null, null, null)); self::assertSame([1], func::call("tv", 1)); self::assertSame([1, 2], func::call("tv", 1, 2)); self::assertSame([1, 2, 3], func::call("tv", 1, 2, 3)); self::assertSame([1, 2, 3, 4], func::call("tv", 1, 2, 3, 4)); # m1o1 self::assertSame([null, 9], func::call("tm1o1")); self::assertSame([null, 9], func::call("tm1o1", null)); self::assertSame([null, null], func::call("tm1o1", null, null)); self::assertSame([null, null], func::call("tm1o1", null, null, null)); self::assertSame([null, null], func::call("tm1o1", null, null, null, null)); self::assertSame([1, 9], func::call("tm1o1", 1)); self::assertSame([1, 2], func::call("tm1o1", 1, 2)); self::assertSame([1, 2], func::call("tm1o1", 1, 2, 3)); self::assertSame([1, 2], func::call("tm1o1", 1, 2, 3, 4)); # m1v self::assertSame([null], func::call("tm1v")); self::assertSame([null], func::call("tm1v", null)); self::assertSame([null, null], func::call("tm1v", null, null)); self::assertSame([null, null, null], func::call("tm1v", null, null, null)); self::assertSame([null, null, null, null], func::call("tm1v", null, null, null, null)); self::assertSame([1], func::call("tm1v", 1)); self::assertSame([1, 2], func::call("tm1v", 1, 2)); self::assertSame([1, 2, 3], func::call("tm1v", 1, 2, 3)); self::assertSame([1, 2, 3, 4], func::call("tm1v", 1, 2, 3, 4)); # m1o1v self::assertSame([null, 9], func::call("tm1o1v")); self::assertSame([null, 9], func::call("tm1o1v", null)); self::assertSame([null, null], func::call("tm1o1v", null, null)); self::assertSame([null, null, null], func::call("tm1o1v", null, null, null)); self::assertSame([null, null, null, null], func::call("tm1o1v", null, null, null, null)); self::assertSame([1, 9], func::call("tm1o1v", 1)); self::assertSame([1, 2], func::call("tm1o1v", 1, 2)); self::assertSame([1, 2, 3], func::call("tm1o1v", 1, 2, 3)); self::assertSame([1, 2, 3, 4], func::call("tm1o1v", 1, 2, 3, 4)); # o1v self::assertSame([9], func::call("to1v")); self::assertSame([null], func::call("to1v", null)); self::assertSame([null, null], func::call("to1v", null, null)); self::assertSame([null, null, null], func::call("to1v", null, null, null)); self::assertSame([null, null, null, null], func::call("to1v", null, null, null, null)); self::assertSame([1], func::call("to1v", 1)); self::assertSame([1, 2], func::call("to1v", 1, 2)); 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()); self::assertInstanceOf(SC::class, $func->invoke([])); 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(); self::assertInstanceOf(C1::class, $i1); self::assertSame(0, $i1->base); $i1 = $func->invoke([]); self::assertInstanceOf(C1::class, $i1); self::assertSame(0, $i1->base); $i1 = $func->invoke([1]); self::assertInstanceOf(C1::class, $i1); self::assertSame(1, $i1->base); $i1 = $func->invoke([1, 2]); self::assertInstanceOf(C1::class, $i1); self::assertSame(1, $i1->base); } private static function invoke_asserts(): array { $inv_ok = function($func) { return func::with($func)->invoke(); }; $inv_ko = function($func) use ($inv_ok) { return function() use ($func, $inv_ok) { return $inv_ok($func); }; }; $bind_ok = function($func, $objet) { return func::with($func)->bind($objet)->invoke(); }; $bind_ko = function($func, $object) use ($bind_ok) { return function() use ($func, $object, $bind_ok) { return $bind_ok($func, $object); }; }; return [$inv_ok, $inv_ko, $bind_ok, $bind_ko]; } function testInvokeStatic() { [$inv_ok, $inv_ko, $bind_ok, $bind_ko] = self::invoke_asserts(); $sc = new SC(); self::assertSame(10, $inv_ok([SC::class, "tstatic"])); self::assertSame(10, $inv_ok([SC::class, "::tstatic"])); self::assertSame(10, $inv_ok([SC::class, "->tstatic"])); self::assertSame(10, $inv_ok([$sc, "tstatic"])); self::assertSame(10, $inv_ok([$sc, "::tstatic"])); self::assertSame(10, $inv_ok([$sc, "->tstatic"])); self::assertException(ValueException::class, $inv_ko([null, "tstatic"])); self::assertException(ValueException::class, $inv_ko([null, "::tstatic"])); self::assertException(ValueException::class, $inv_ko([null, "->tstatic"])); self::assertSame(10, $bind_ok([null, "tstatic"], SC::class)); self::assertSame(10, $bind_ok([null, "::tstatic"], SC::class)); self::assertSame(10, $bind_ok([null, "->tstatic"], SC::class)); self::assertSame(10, $bind_ok([null, "tstatic"], $sc)); self::assertSame(10, $bind_ok([null, "::tstatic"], $sc)); self::assertSame(10, $bind_ok([null, "->tstatic"], $sc)); } function testInvokeMethod() { [$inv_ok, $inv_ko, $bind_ok, $bind_ko] = self::invoke_asserts(); $sc = new SC(); self::assertException(ReflectionException::class, $inv_ko([SC::class, "tmethod"])); self::assertException(ReflectionException::class, $inv_ko([SC::class, "::tmethod"])); self::assertException(ReflectionException::class, $inv_ko([SC::class, "->tmethod"])); self::assertSame(11, $inv_ok([$sc, "tmethod"])); self::assertException(ReflectionException::class, $inv_ko([$sc, "::tmethod"])); self::assertSame(11, $inv_ok([$sc, "->tmethod"])); self::assertException(ValueException::class, $inv_ko([null, "tmethod"])); self::assertException(ValueException::class, $inv_ko([null, "::tmethod"])); self::assertException(ValueException::class, $inv_ko([null, "->tmethod"])); self::assertException(ReflectionException::class, $bind_ko([null, "tmethod"], SC::class)); self::assertException(ReflectionException::class, $bind_ko([null, "::tmethod"], SC::class)); self::assertException(ReflectionException::class, $bind_ko([null, "->tmethod"], SC::class)); self::assertSame(11, $bind_ok([null, "tmethod"], $sc)); self::assertException(ReflectionException::class, $bind_ko([null, "::tmethod"], $sc)); self::assertSame(11, $bind_ok([null, "->tmethod"], $sc)); } function testArgs() { $func = function(int $a, int $b, int $c): int { return $a + $b + $c; }; self::assertSame(6, func::call($func, 1, 2, 3)); self::assertSame(6, func::call($func, 1, 2, 3, 4)); self::assertSame(6, func::with($func)->invoke([1, 2, 3])); self::assertSame(6, func::with($func, [1])->invoke([2, 3])); self::assertSame(6, func::with($func, [1, 2])->invoke([3])); self::assertSame(6, func::with($func, [1, 2, 3])->invoke()); self::assertSame(6, func::with($func, [1, 2, 3, 4])->invoke()); } function testRebind() { $func = func::with([C1::class, "tmethod"]); self::assertSame(11, $func->bind(new C1(0))->invoke()); self::assertSame(12, $func->bind(new C1(1))->invoke()); self::assertException(ValueException::class, function() use ($func) { $func->bind(new C0())->invoke(); }); } } } namespace { function tsimple(): int { return 0; } function tm1($a): array { return [$a]; } function to1($b=9): array { return [$b]; } function tv(...$c): array { return [...$c]; } function tm1o1($a, $b=9): array { return [$a, $b]; } function tm1v($a, ...$c): array { return [$a, ...$c]; } function tm1o1v($a, $b=9, ...$c): array { return [$a, $b, ...$c]; } function to1v($b=9, ...$c): array { return [$b, ...$c]; } } namespace nur\sery\php\impl { function ntsimple(): int { return 0; } class SC { static function tstatic(): int { return 10; } function tmethod(): int { return 11; } } class C0 { function __construct() { } static function tstatic(): int { return 10; } function tmethod(): int { return 11; } } class C1 { function __construct(int $base=0) { $this->base = $base; } public int $base; static function tstatic(): int { return 10; } function tmethod(): int { return 11 + $this->base; } } }