PHPackages                             tightenco/overload - 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. tightenco/overload

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

tightenco/overload
==================

Method overloading for PHP

v0.1.3(5y ago)11395292MITPHPPHP ^7.1

Since Oct 26Pushed 3y ago6 watchersCompare

[ Source](https://github.com/tighten/overload)[ Packagist](https://packagist.org/packages/tightenco/overload)[ Docs](https://github.com/tightenco/overload)[ RSS](/packages/tightenco-overload/feed)WikiDiscussions main Synced 3d ago

READMEChangelog (4)Dependencies (3)Versions (5)Used By (2)

[![Overload logo](https://raw.githubusercontent.com/tighten/overload/main/overload-banner.png)](https://raw.githubusercontent.com/tighten/overload/main/overload-banner.png)

Method overloading for PHP
==========================

[](#method-overloading-for-php)

[![Run tests](https://github.com/tighten/takeout/workflows/Run%20tests/badge.svg?branch=main)](https://github.com/tighten/overload/actions?query=workflow%3A%22Run+PHP+Tests%22)[![Latest Version on Packagist](https://camo.githubusercontent.com/5df27a51075c0e3a039d8aa22c7bded26d1b7c712fc10859b104a9678275739e/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7469676874656e636f2f6f7665726c6f61642e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/tightenco/overload)[![Total Downloads](https://camo.githubusercontent.com/6503e69bd199e04fc50cea78b2b58db62554da3c6ca1bb35476ad422b6e932ef/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f7469676874656e636f2f6f7665726c6f61642e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/tightenco/overload)

NOTE: This is a beta release. It's Adam's original code almost exactly, and his docs; if a lot of folks are interested, we can, as a community, find its limits and edges and where it needs to grow. **Please note that, while all credit goes to Adam for writing this, the responsibility for maintaining it is not on him. Tighten will do our best to keep it up, but if this goes anywhere it will be because of community support. This is a beta release and does not carry with it any promise that it doesn't have bugs or holes.**

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

[](#installation)

You can install the package via composer:

```
composer require tightenco/overload
```

Usage
-----

[](#usage)

This package gives you a declarative way to support multiple signatures for the same method.

### Basic Example

[](#basic-example)

Say we have a `Ticket` class with a `holdUntil` method that lets us put that ticket on hold until a certain date and time by passing in a DateTime object:

```
class Ticket extends Model
{
    // ...

    public function holdUntil(DateTime $dateTime)
    {
        $this->update(['hold_until' => $dateTime]);
    }

    // ...
}
```

...but now you decide it would be convenient if it could also accept a well-formatted date string.

Normally you'd do something like this:

```
class Ticket extends Model
{
    // ...

    public function holdUntil($dateTime)
    {
        if (is_string($dateTime)) {
            $dateTime = Carbon::parse($dateTime);
        }

        $this->update(['hold_until' => $dateTime]);
    }

    // ...
}
```

The overloadable trait allows you to essentially pattern match in a declarative way instead of conditionally checking arguments:

```
class Ticket extends Model
{
    use Overloadable;

    // ...

    public function holdUntil(...$args)
    {
        return $this->overload($args, [
            function (string $dateTime) {
               $this->update(['hold_until' => Carbon::parse($dateTime)]);
            },
            function (DateTime $dateTime) {
               $this->update(['hold_until' => $dateTime]);
            },
        ]);
    }

    // ...
}
```

If you wanted to avoid that duplication, you could even do this wild recursive madness:

```
class Ticket extends Model
{
    use Overloadable;

    // ...

    public function holdUntil(...$args)
    {
        return $this->overload($args, [
            function (string $dateTime) {
               $this->holdUntil(Carbon::parse($dateTime));
            },
            function (DateTime $dateTime) {
               $this->update(['hold_until' => $dateTime]);
            },
        ]);
    }

    // ...
}
```

### A cooler example

[](#a-cooler-example)

You might be thinking:

> "Uhhh bro, that looks like even more code."

Yeah, because that example is boring. This one is a bit more fun.

I've always wanted Laravel's `validate` controller helper to accept a closure as its last parameter that let me return whatever HTTP response I wanted if validation failed.

But the method signature for `validate` takes like a million things and I don't want to pass a ton of empty arrays, for example:

```
public function store()
{
    //                             Super grim! 😭
    //                                ⬇️  ⬇️
    $this->validate($request, $rules, [], [], function ($errors) {
        return response()->json([
            'someOtherInfo' => 'toInclude',
            'errors' => $errors
        ], 422);
    });
}
```

I'd love if I could just do:

```
public function store()
{
    $this->validate($request, $rules, function ($errors) {
        return response()->json([
            'someOtherInfo' => 'toInclude',
            'errors' => $errors
        ], 422);
    });
}
```

...and have it magically work, knowing I clearly don't care about the `$messages` or `$customAttributes` arguments, but can you imagine how gross it would be to add those checks inside the `validate` method to do all this argument counting and type checking?!

Check out how it would work with this badass trait from the gods:

```
trait ValidatesRequests
{
    // ...

    public function validate(...$args)
    {
        return $this->overload($args, [
            function ($request, $rules, Closure $callback) {
                return $this->validateRequest($request, $rules, [], [], $callback);
            },
            function ($request, $rules, $messages, Closure $callback) {
                return $this->validateRequest($request, $rules, $messages, [], $callback);
            },
            'validateRequest',
        ]);
    }

    // Move the real logic into a new private function...
    protected function validateRequest(Request $request, array $rules, array $messages = [], array $customAttributes = [], Closure $onErrorCallback = null)
    {
        $validator = $this->getValidationFactory()->make($request->all(), $rules, $messages, $customAttributes);

        if ($validator->fails()) {
            $this->throwValidationException($request, $validator, $onErrorCallback);
        }
    }

    // ...
}
```

### Matching Options

[](#matching-options)

Overloadable doesn't just work with closures; you can do all sorts of crazy stuff!

Check out this example from the test:

```
class SomeOverloadable
{
    use Overloadable;

    public function someMethod(...$args)
    {
        return $this->overload($args, [
            // Call this closure if two args are passed and the first is an int
            function (int $a, $b) {
                return 'From the Closure';
            },

            // Call this method if the args match the args of `methodA` (uses reflection)
            'methodA',

            // Call this method if the args match the args of `methodB` (uses reflection)
            'methodB',

            // Call methodC if exactly 2 arguments of any type are passed
            'methodC' => ['*', '*'],

            // Call methodD if 3 args are passed and the first is an array
            'methodD' => ['array', '*', '*'],

            // Call methodE if 3 args are passed and the last is a closure
            'methodE' => ['*', '*', Closure::class],
        ]);
    }

    private function methodA($arg1)
    {
        return 'Method A';
    }

    private function methodB(\DateTime $arg1, array $arg2, int $arg3)
    {
        return 'Method B';
    }

    private function methodC($arg1, $arg2)
    {
        return 'Method C';
    }

    private function methodD($arg1, $arg2, $arg3)
    {
        return 'Method D';
    }

    private function methodE($arg1, $arg2, $arg3)
    {
        return 'Method E';
    }
}
```

Methods are matched in the order they are specified when you call `overload`.

### Notes from Adam's original work

[](#notes-from-adams-original-work)

I'm still just hacking around with this and there's probably a bunch of things I'm missing.

For example, it just occurred to me that I haven't really considered how the reflection-based detection stuff should handle optional arguments, and off the top of my head I don't even know what it should do ¯\\*(ツ)*/¯

Either way, I think it's some pretty fun code and I thought it was pretty cool that we could even come up with an API for it at all.

Upcoming plans:
---------------

[](#upcoming-plans)

- Release beta with Adam's exact code
- Discover known shortcomings and document as issues (for starters, optional arguments and the forthcoming union types)
- Fix ^^
- Profit? 🤣 OK, not profit.

### Testing

[](#testing)

```
composer test
```

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)

The idea of method overloading comes from other languages that have it natively. I (Matt) have heard about it multiple times, including from my friend Adam Wathan, so when I decided to finally build something about it, I got a few hours in and then paused and asked Adam if he'd ever seen anyone build it. Turns out... he had.

He sent me a link to this [gist](https://gist.github.com/adamwathan/120f5acb69ba84e3fa911437242796c3). However, Adam didn't want to maintain a package, so, with his blessing, I spun this off to make it more accessible to the rest of the world.

- [Adam Wathan](https://github.com/adamwathan)
- [Matt Stauffer](https://github.com/mattstauffer)
- [All Contributors](../../contributors)

License
-------

[](#license)

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

###  Health Score

32

—

LowBetter than 72% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity30

Limited adoption so far

Community25

Small or concentrated contributor base

Maturity46

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 61.3% 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 ~105 days

Total

4

Last Release

2075d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/151829?v=4)[Matt Stauffer](/maintainers/mattstauffer)[@mattstauffer](https://github.com/mattstauffer)

---

Top Contributors

[![mattstauffer](https://avatars.githubusercontent.com/u/151829?v=4)](https://github.com/mattstauffer "mattstauffer (19 commits)")[![driftingly](https://avatars.githubusercontent.com/u/194221?v=4)](https://github.com/driftingly "driftingly (2 commits)")[![shaneburns](https://avatars.githubusercontent.com/u/12102883?v=4)](https://github.com/shaneburns "shaneburns (2 commits)")[![chapeupreto](https://avatars.githubusercontent.com/u/834048?v=4)](https://github.com/chapeupreto "chapeupreto (2 commits)")[![faxblaster](https://avatars.githubusercontent.com/u/4378273?v=4)](https://github.com/faxblaster "faxblaster (2 commits)")[![szepeviktor](https://avatars.githubusercontent.com/u/952007?v=4)](https://github.com/szepeviktor "szepeviktor (1 commits)")[![krievley](https://avatars.githubusercontent.com/u/7070136?v=4)](https://github.com/krievley "krievley (1 commits)")[![localheinz](https://avatars.githubusercontent.com/u/605483?v=4)](https://github.com/localheinz "localheinz (1 commits)")[![peter279k](https://avatars.githubusercontent.com/u/9021747?v=4)](https://github.com/peter279k "peter279k (1 commits)")

---

Tags

phptightencoOverloadoverloadable

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/tightenco-overload/health.svg)

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

###  Alternatives

[imanghafoori/laravel-anypass

A minimal yet powerful package to help you in development.

21421.6k](/packages/imanghafoori-laravel-anypass)[jshannon63/jsoncollect

Supercharge your JSON using collections

154.9k1](/packages/jshannon63-jsoncollect)

PHPackages © 2026

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