The missing method overloading feature for PHP.
composer require typhoon/overloading
To mark methods handleInt
and handleString
as overloading method handle
,
add #[Overload('handle')]
attribute to handleInt
and handleString
and
call Overload::call()
from handle
. You do not need to pass arguments to Overload::call()
,
this happens automagically. However, return Overload::call()
explicitly if you need to.
After this you will be able to call handle
with any arguments and reach overloading methods
when their signature matches.
use Typhoon\Overloading\Overload;
final class WhateverHandler
{
public function handle(mixed ...$args): string
{
return Overload::call();
}
#[Overload('handle')]
public function handleInt(int $int): string
{
return __METHOD__;
}
#[Overload('handle')]
public function handleString(string $string): string
{
return __METHOD__;
}
#[Overload('handle')]
public function handleStdClass(\stdClass $object): string
{
return __METHOD__;
}
#[Overload('handle')]
public function handleNamedOptionalArguments(int $int = 0, float $float = M_E): string
{
return __METHOD__;
}
}
$handler = new WhateverHandler();
// WhateverHandler::handleInt
var_dump($handler->handle(300));
// WhateverHandler::handleString
var_dump($handler->handle('Hello world!'));
// WhateverHandler::handleStdClass
var_dump($handler->handle(new \stdClass()));
// WhateverHandler::handleNamedOptionalArguments
var_dump($handler->handle(float: 1.5));
// WhateverHandler::handleNamedOptionalArguments
var_dump($handler->handle());
// No matching overloading methods for WhateverHandler::handle(string, bool).
var_dump($handler->handle('Hey!', true));
Well, using overloading is obviously slower, than calling a method directly, but not awfully slower.
Here's a simple benchmark for the WhateverHandler
:
// warm up
$handler->handle();
\DragonCode\Benchmark\Benchmark::start()
->withoutData()
->round(2)
->compare([
'direct call' => static fn (): string => $handler->handleNamedOptionalArguments(),
'overloaded call' => static fn (): string => $handler->handle(),
]);
------- ---------------- -------------------
# direct call overloaded call
------- ---------------- -------------------
min 0 ms - 0 bytes 0 ms - 0 bytes
max 0 ms - 0 bytes 0.02 ms - 0 bytes
avg 0 ms - 0 bytes 0 ms - 0 bytes
total 0.95 ms 1.16 ms
------- ---------------- -------------------
Order - 1 - - 2 -
------- ---------------- -------------------
It's important to understand that memoization plays a very important role here. CLI workers and applications, served
via Roadrunner, for instance, will benefit from this. For PHP-FPM you can enable file cache suitable for OPcaching via
Overload::useFileCache('/path/to/cache');
.
- Finish tests.
- Explain caching in README.
- Optimize generated code.
- Inherit attributes from upstream method declarations.
- Allow to warm up classes.
- Psalm plugin.
- PHPStan plugin.
- Support static analysis types.