henzeb / closure
使用完全限定名称(FQCN)调用类,更多功能!
Requires
- php: ^8.0
Requires (Dev)
- infection/infection: ^0.26.19
- phpstan/phpstan: ^1.4
- phpunit/phpunit: ^9.6.6|^10
README
在PHP中,我们有 Closure::fromCallable()
。遗憾的是,它不与FQCN字符串一起工作。
此包提供了一个从fromCallable扩展的功能,允许可调用的类的FQCN字符串成为闭包。
安装
只需使用以下命令安装。
composer require henzeb/closure
用法
use function Henzeb\Closure\closure; class InvokableClass { public function __invoke() { print 'Hello World!'; } } class ReturnsClosures { public function __invoke(): Closure { print fn()=>'Hello World!'; } } class NotInvokableClass { public function invoke() { print 'Hello World!'; } } function helloWorld() { print 'Hello World!'; } closure(Invokable::class)(); // prints Hello World! closure(new InvokableClass)(); // prints Hello World! closure(ReturnsClosure::class)(); // prints Hello World! closure(new ReturnsClosure())(); // prints Hello World! closure('helloWorld')(); // prints Hello World! closure( function(){ print 'Hello World!' } ); // prints Hello World!; closure(NotInvokable::class); // throws TypeError
解析
有时你可能需要告诉 closure
如何解析你的可调用对象
use function Henzeb\Closure\closure; class InvokableClass { public function __construct(private $message) { } public function __invoke() { print $this->message; } } closure( Invokable::class, fn(string $class) => $class('Hello World!') ); // prints Hello World!
注意:虽然 closure
在创建时可能会抛出TypeError,但FQCN的解析发生在实际调用新创建的闭包时。解析只发生一次。除非可调用的方法返回一个闭包,那么解析将首先发生以返回此闭包。
绑定
闭包因其能够绑定和更改作用域的能力而非常可爱的小东西。如果你有这种需求,可以使用 bind
。
use function Henzeb\Closure\bind; bind( fn()=> // do what you need , $anyThis )('your Arg');
要使用FCQN或可调用的类进行绑定,__invoke
函数必须返回一个闭包。请注意返回类型!没有它将失败。
class InvokableClass { public function __invoke($hello): Closure { return $anyThis->hello($hello); } }
use function Henzeb\Closure\bind; bind(InvokableClass::class, $anyThis)('your Arg'); bind(InvokableClass::class, $anyThis, AnyScope::class)('your Arg'); bind(new InvokableClass, $anyThis)('your Arg');
在幕后,绑定将使用 closure
获取一个闭包,并将新的 this
和作用域绑定到它上。然后它返回你可以使用的闭包。
调用
您还可以直接使用 call
调用一个(绑定的)闭包。
use function Henzeb\Closure\call; call( fn()=>'Hello world!' ); // returns Hello World! call( InvokableClass::class ); // returns whatever your callable returns call(InvokableClass::class, $anyThis); // returns whatever your callable returns call( InvokableClass::class, $anyThis, AnyScope::class ); // returns whatever your callable returns call(new InvokableClass, $anyThis); // returns whatever your callable returns call( InvokableClass::class, $anyThis, resolve: fn($class) => new $class('Hello World!') ); // returns whatever your callable returns call( fn()=>'Hello world!' , $anyThis ); // returns Hello World!
调用不同的方法
在某些情况下,你可能想要包装一个不可调用的FQCN或类。每个函数都接受一个名为 invoke
的参数。
class NonInvokable { public function hello() { print 'Hello World!'; } }
use function Henzeb\Closure\closure; use function Henzeb\Closure\bind; use function Henzeb\Closure\call; closure(NonInvokable::class, invoke: 'hello')(); // prints Hello World!; bind(NonInvokable::class, $newthis, invoke: 'hello')(); // prints Hello World!; call(NonInvokable::class, $newthis, invoke: 'hello'); // prints Hello World!;
可调用
要测试一个对象是否可调用,因此可以成为闭包。该函数接受任何值。
use function Henzeb\Closure\invokable; invokable(NonInvokable::class); // returns false invokable(NonInvokable::class, 'hello'); // returns true invokable(InvokableClass::class); // returns true invokable([]); // returns false invokable(STDIN); // returns false
包装
有时你可能期望一个布尔值或一个可调用对象。使用 closure
,这将失败。使用 wrap
,任何不可调用的东西都将被包装在一个闭包中。
use function Henzeb\Closure\wrap; wrap(NonInvokable::class)(); // returns NonInvokable instance wrap(true)(); // returns true wrap(false)(); // returns true wrap(InvokableClass::class)(); // returns what __invoke would return wrap( InvokableClass::class, invoke: 'invokableMethod' )(); // returns what invokableMethod would return wrap([])(); // returns an empty array wrap(STDIN)(); // returns the STDIN stream
绑定
在某些情况下,你可能想知道闭包或可调用对象的当前绑定。
use function Henzeb\Closure\binding; binding(function(){})->getScope(); // returns $newScope value binding(function(){})->getThis(); // returns $newThis value
访问静态变量
当你有使用 use
子句的闭包,或者在闭包中使用静态变量时,你可以使用以下方式访问它们
use function Henzeb\Closure\binding; $myVariable = 'Hello World!'; $closure = function() use ($myVariable) { static $myStaticVariable; $myStaticVariable = 'Hello World!' } binding($closure)->get('myVariable'); // returns Hello World! binding($closure)->get('myOtherVariable'); // returns null. binding($closure)->get('myStaticVariable'); // returns null. $closure(); //calling the closure binding($closure)->get('myStaticVariable'); // returns Hello World!
调试信息
你可以使用 var_dump
来打印所有变量的列表。
use function Henzeb\Closure\binding; var_dump(binding(fn()=>true));
这将返回一个包含当前 scope
、当前 this
以及与其关联的任何静态变量的数组。
测试此包
composer test
变更日志
有关最近更改的更多信息,请参阅变更日志。
贡献
有关详细信息,请参阅贡献指南。
安全性
如果你发现任何与安全性相关的问题,请通过电子邮件henzeberkheij@gmail.com联系,而不是使用问题跟踪器。
致谢
许可协议
GNU AGPLv。有关更多信息,请参阅许可文件。