您好,欢迎访问一九零五行业门户网

浅析PHP8.0特性:Named Parameter(命名参数)

年前花了点时间,对yar的性能做了一些做了一些提升,但是也遇到一个让我有点不舒服的当初没有良好设计遗留的问题,就是在并行调用rpc的时候,现在的方法原型是:
public static yar_concurrent_client::call(string $uri, string $method, ?array $arguments = null, ?callable $callback = null, ?callable $error_callback = null, ?array $options = null):null|int|bool {}
是不是一看就很头大?
因为在实际的使用过程中,很有可能回调函数和错误回调函数是空的,因为可以真正发起调用的时候,也就是在loop重全局指定:
yar_concurrent_client::loop(?callable $callback = null, ?callable $error_callback = null, ?array $options = null):?bool {}
而很多时候$options是有用的,根据调用相关,所以就导致,实际的使用的时候,大量的并行调用的代码会在参数中写很多的null, 类似:
yar_concurrent_clinet::call(https://xxx.com/api, method, array(arguments), null, null, array(yar_opt_header=>array(header:val1));yar_concurrent_clinet::call(https://xxx.com/api, method, array(arguments), null, null, array(yar_opt_header=>array(header:val2));yar_concurrent_clinet::call(https://xxx.com/api, method, array(arguments), null, null, array(yar_opt_header=>array(header:val2));yar_concurrent_clinet::call(https://xxx.com/api, method, array(arguments), null, null, array(yar_opt_header=>array(header:val4));
于是我一直想如何能让这样的调用更优雅一些,曾经一度我想使用多态,或者新增一个api,类似:
public static yar_concurrent_client::callarray(array $arguments):null|int|bool {}
但强迫症让我觉得这样做,遗祸无穷, 今天早上我突然想起以前曾经看到过的一个rfc,于是找了半天,发现早在php5.6的时候,就commit了, 但反正我比较老派,新特性研究的少,也是没怎么用过,就不知道大家是否会用过了。 ?
就是今天要介绍的第一个特性:argument unpacking。
argument unpacking我们知道php支持可变参数,也就是variadic function. 比如对于如下的函数定义:
function variadic(...$arguments) {    var_dump($arguments);}
注意参数的定义,使用了三个点…(ellipsis符号), 意思就是无论你在调用这个函数的时候传递了多少个参数,这些参数都会被打包成一个名字为$arguments的数组:
variadic();//output: array(0) { }variadic(null);//output: array(1) { [0]=> null }variadic(foo, bar);//output: array(2) { [0]=> string(3) foo  [1]=> string(3) bar }variadic(null, array(), dummy);//output: array(3) { [0]=> null [1]=>[] [2]=> string(5) dummy }
当然,这个不是我们今天要用到的,这个特性还有一个对应的在调用时刻使用的兄弟形式,叫做argument unpacking:
比如,类似上面我的那个问题,我们定义了一个函数
function dummy($a, $b = null, $c = null, $d = null, $e = null) {    var_dump($a, $b, $c, $d, $e);}

如果大部分情况下我们的参数b, c,  d都是null, 但是e可能需要传递,那我们就可以使用argument unpacking来避免代码中大量的null参数,类似:
$arguments = array(    first argument,    null,  null,  null,    fifth argument,); dummy(...$arguments); //output:// string(14) first argument// null// null// null// string(14) fifth argument
注意在调用的时候,我也使用了…,这里的意思就是,把…后面的数组解开,按照顺序分别依次传递给被调用的函数,第一个元素对应第一个参数, 第二个对应第二个。
但是注意,这里的位置是跟填充位置相关的,跟索引无关,也就是说:
$arguments = array(    4=> first argument,    0=> fifth argument),
这样的形式, 索引4依然是被认为是第一个参数。
想到这个以后,我就突然发现,我不需要给yar引入新东西了,最开的例子就可以变成:
$arguments = array(    https://xxx.com/api,    method,    array(arguments),    null, null,     options => array(yar_opt_header => array(header:val1))yar_concurrent_clinet::call(...$arguments); $arguments[options][yar_opt_hader] = [header:val2];yar_concurrent_clinet::call(...$arguments); $arguments[options][yar_opt_hader] = [header:val3];yar_concurrent_clinet::call(...$arguments); $arguments[options][yar_opt_hader] = [header:val4];yar_concurrent_clinet::call(...$arguments);yar_concurrent_clinet::call(...$arguments);
你以为这就完了么?
考虑到如上的代码,还是有一个问题,就是需要构造一个中间数组,对于强迫症的我们来说,总还是觉得会有点,那啥…
但其实我们还可以利用php8.0中引入的另外一个rfc, named parameter:
named parameter在php8.0以后,容许用户在传递参数的时候,指定参数名字, 比如还是对于上面的例子函数:
function dummy($a, $b = null, $c = null, $d = null, $e = null) {    var_dump($a, $b, $c, $d, $e);}

现在我们可以在调用的时候,指定要传递的参数名字,比如:
dummy(a:dummy, e:foo);//output:// string(5) dummy// null// null// null// string(3) foo
也就是说,我指定了传递给a和e参数,没有指定的就是默认缺省值,你甚至可以不按声明顺序来,比如:
dummy(e:foo, a:dummy);
输出结果也是一样的。
这样以来,开头的代码就可以变成:
yar_concurrent_client::call(https://xxx.com/api, method, arguments:array(arguments), options:array(yar_opt_header=>array(header:val1)));yar_concurrent_client::call(https://xxx.com/api, method, arguments:array(arguments), options:array(yar_opt_header=>array(header:val2)));yar_concurrent_client::call(https://xxx.com/api, method, arguments:array(arguments), options:array(yar_opt_header=>array(header:val3)));yar_concurrent_client::call(https://xxx.com/api, method, arguments:array(arguments), options:array(yar_opt_header=>array(header:val4)));
你就可以在调用的时候,想传那个传那个,想怎么传就怎么传
虽然代码相比argument unpacking还是有点长,但是既解决了不用写那么多null,又不会引入新的中间变量。
于是,问题完美解决,我也不用引入新的api了 :)
原文地址:https://www.laruence.com/2022/05/10/6192.html
推荐学习:《php视频教程》
以上就是浅析php8.0特性:named parameter(命名参数)的详细内容。
其它类似信息

推荐信息