PHPackages                             henzeb/closure - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. henzeb/closure

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

henzeb/closure
==============

Invoke classes using their FQCN, and more!

v1.7.0(2y ago)081↓50%1AGPL-3.0-onlyPHPPHP ^8.0CI passing

Since May 20Pushed 4mo ago1 watchersCompare

[ Source](https://github.com/henzeb/closure)[ Packagist](https://packagist.org/packages/henzeb/closure)[ Docs](https://github.com/henzeb/closure)[ RSS](/packages/henzeb-closure/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (9)Dependencies (3)Versions (10)Used By (1)

Closure
=======

[](#closure)

[![Build Status](https://github.com/henzeb/closure/workflows/tests/badge.svg)](https://github.com/henzeb/closure/actions)[![Latest Version on Packagist](https://camo.githubusercontent.com/19e6ed447876d6db590e32882ef201ce31a19528dc35009b7d0b5b29d1054930/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f68656e7a65622f636c6f737572652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/henzeb/closure)[![Total Downloads](https://camo.githubusercontent.com/b000758b4105f3e75c905d248a6efb5118aeb8a6bbb6346916b20c340ff1369a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f68656e7a65622f636c6f737572652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/henzeb/closure)[![License](https://camo.githubusercontent.com/c71447ffe0976487ba00cdbb351c90bee348f342d5f73bd00aeefd9f6619322a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f68656e7a65622f636c6f73757265)](https://packagist.org/packages/henzeb/closure)

In PHP, whe have `Closure::fromCallable()`. Sadly, it does not work with FQCN strings.

This package ships a function that extends fromCallable allowing FQCN strings of invokable classes to become closures.

Installation
------------

[](#installation)

Just install with the following command.

```
composer require henzeb/closure
```

usage
-----

[](#usage)

```
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
```

### Resolving

[](#resolving)

Sometimes you may need to tell `closure` how to resolve your callable

```
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!
```

Note: While `closure` may throw a TypeError on creation, resolving of FQCN happens on actually calling the newly created closure. Resolving happens only the first time. Except when the invokable method returns a Closure, then the resolving takes place first to return this closure.

### Binding

[](#binding)

Closures are adorable hacky little creatures due to their ability to bind and change scopes. If you ever have that need you can use `bind`.

```
use function Henzeb\Closure\bind;

bind(
    fn()=> // do what you need
    , $anyThis
)('your Arg');
```

To use a FCQN or invokable class with binding, the `__invoke` function must return a Closure. Please note the return type! Without, it wil fail.

```
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');
```

Bind will under the hood use `closure` to get a closure, and then binds the new `this` and scope to it. It then returns a Closure you can use.

Calling
-------

[](#calling)

You can also directly call a (binded) closure using `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!
```

Invoking different methods
--------------------------

[](#invoking-different-methods)

In some cases you'd like to wrap a non-callable FQCN or class. Each function accepts a parameter named `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!;
```

invokable
---------

[](#invokable)

To test an object is invokable, and thus can become a closure. The function accepts any value.

```
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
```

Wrapping
--------

[](#wrapping)

Sometimes you may expect a boolean or a callable. using `closure`, This would fail. Using `wrap`, anything that's not invokable, will be wrapped inside a closure.

```
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
```

Bindings
--------

[](#bindings)

In some cases you might want to know the current binding of a closure or invokable.

```
use function Henzeb\Closure\binding;

binding(function(){})->getScope(); // returns $newScope value
binding(function(){})->getThis(); // returns $newThis value
```

### accessing static variables

[](#accessing-static-variables)

When you have closures that uses the `use` clause or when you use static variables inside your closure you can access them with the following:

```
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!
```

### debug info

[](#debug-info)

You can use `var_dump` to print a list of all variables.

```
use function Henzeb\Closure\binding;

var_dump(binding(fn()=>true));
```

This will return an array with the current `scope`, the current `this` and any static variables associated with it.

Testing this package
--------------------

[](#testing-this-package)

```
composer test
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](CONTRIBUTING.md) for details.

Security
--------

[](#security)

If you discover any security related issues, please email  instead of using the issue tracker.

Credits
-------

[](#credits)

- [Henze Berkheij](https://github.com/henzeb)

License
-------

[](#license)

The GNU AGPLv. Please see [License File](LICENSE.md) for more information.

###  Health Score

34

—

LowBetter than 77% of packages

Maintenance50

Moderate activity, may be stable

Popularity12

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity55

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1 days

Total

9

Last Release

1084d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/15928532?v=4)[henzeb](/maintainers/henzeb)[@henzeb](https://github.com/henzeb)

---

Top Contributors

[![henzeb](https://avatars.githubusercontent.com/u/15928532?v=4)](https://github.com/henzeb "henzeb (12 commits)")

---

Tags

callableclosurehenzebinvokablefqcn

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/henzeb-closure/health.svg)

```
[![Health](https://phpackages.com/badges/henzeb-closure/health.svg)](https://phpackages.com/packages/henzeb-closure)
```

###  Alternatives

[php-di/invoker

Generic and extensible callable invoker

26857.8M56](/packages/php-di-invoker)[zenstruck/callback

Callable wrapper to validate and inject arguments.

569.6M4](/packages/zenstruck-callback)[phpfluent/callback

Allows you execute callbacks in a more dynamic way

1159.2k1](/packages/phpfluent-callback)[rybakit/arguments-resolver

ArgumentsResolver allows you to determine the arguments to pass to a function or method.

26107.7k7](/packages/rybakit-arguments-resolver)[raphhh/trex-reflection

Reflection helpers for callables and types

14324.0k10](/packages/raphhh-trex-reflection)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
