upscale / stdlib-overloading
PHP7函数/方法参数重载
1.0.3
2020-02-23 05:02 UTC
Requires
- php: >=7.1
Requires (Dev)
- phpunit/phpunit: ^7.0
This package is auto-updated.
Last update: 2024-09-18 06:52:20 UTC
README
此库引入了函数/方法重载——根据输入参数进行不同的实现。
特性
安装
该库通过Composer作为依赖项进行安装
composer require upscale/stdlib-overloading
用法
语法
重载自定义函数/方法
<?php declare(strict_types=1); use function Upscale\Stdlib\Overloading\overload; function func(...$args) { return overload( function (int $num1, int $num2) { // ... }, function (string $str1, string $str2) { // ... } // ... )(...$args); }
可以声明任意数量的有效callable
实现。顺序定义了评估优先级。
调用重载的函数
func(1, 2); func('a', 'b');
示例
一个可以处理普通整数、任意长度的GMP整数和Money对象的算术计算器。
<?php declare(strict_types=1); use function Upscale\Stdlib\Overloading\overload; class Money { private $amount; private $currency; public function __construct(int $amount, string $currency) { $this->amount = $amount; $this->currency = $currency; } public function add(self $sum): self { if ($sum->currency != $this->currency) { throw new \InvalidArgumentException('Money currency mismatch'); } return new self($this->amount + $sum->amount, $this->currency); } } class Calculator { public function add(...$args) { return overload( function (int $num1, int $num2): int { return $num1 + $num2; }, function (\GMP $num1, \GMP $num2): \GMP { return gmp_add($num1, $num2); }, function (Money $sum1, Money $sum2): Money { return $sum1->add($sum2); } )(...$args); } } $calc = new Calculator(); $one = gmp_init(1); $two = gmp_init(2); $oneUsd = new Money(1, 'USD'); $twoUsd = new Money(2, 'USD'); print_r($calc->add(1, 2)); // 3 print_r($calc->add($one, $two)); // GMP Object([num] => 3) print_r($calc->add($oneUsd, $twoUsd)); // Money Object([amount:Money:private] => 3 [currency:Money:private] => USD) print_r($calc->add(1.25, 2)); // TypeError: Argument 1 passed to Calculator::{closure}() must be an instance of Money, float given
架构
重载机制利用了PHP7的原生类型系统,并依赖于声明严格的类型注解。它按声明的顺序遍历实现回调,并尝试用提供的参数调用每个回调。返回第一个兼容调用的结果,并丢弃后续的回调。
限制
PHP引擎允许传递给函数/方法的运行时参数多于其签名声明中计数的参数。多余的参数将被静默丢弃,不会触发任何可捕获的错误,甚至不包括ArgumentCountError
。解决方案是在更具体的较长的签名之前声明更不具体的较短的签名,具有匹配的参数子集。
可选参数存在问题,因为它们仅在调用时与所需参数的较短签名兼容。考虑以下无法通过重新排序解决的模糊声明
overload( function (int $num1, int $num2) { // ... }, function (int $num1) { // ... }, function (int $num1, string $str2 = 'default') { // Unreachable because preceding declaration matches first and swallows excess arguments // ... } )
解决方案是验证参数数量不超过声明
overload( function (int $num1, int $num2) { // ... }, function (int $num1) { if (func_num_args() > 1) { throw new \ArgumentCountError('Too many arguments provided'); } // ... }, function (int $num1, string $str2 = 'default') { // Reachable with the optional argument passed, but still unreacable without it // ... } )
贡献
欢迎提交带有修复和改进的拉取请求!
许可证
版权所有 © Upscale Software。保留所有权利。