henzeb/closure

使用完全限定名称(FQCN)调用类,更多功能!

v1.7.0 2023-05-31 06:12 UTC

This package is auto-updated.

Last update: 2024-08-30 01:38:31 UTC


README

Build Status Latest Version on Packagist Total Downloads License

在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。有关更多信息,请参阅许可文件