在所有的编程语言中,办法或者函数,都能够传递一些参数进来进行业务逻辑的解决或者计算。这没什么可说的,然而在 PHP 中,办法的参数还有许多十分有意思的能力,上面咱们就来说说这方面的内容。
援用参数
波及到值传递和援用传递的问题。在失常状况下,咱们应用值传递的时候,变量是进行了拷贝,办法内外的变量不会共享内存。也就是说,在办法体中批改了变量的值,办法内部的变量不会产生变动。而援用传递则是传递的变量的内存地值。办法内外的变量能够看做是同一个变量,比方:
$a = 1;
function test(&$arg){$arg++;}
test($a);
echo $a; // 2
为参数加上 & 标识,就表明这个参数是援用传递的参数。如果没有加这个标识,则所有的根本类型参数都会以值的形式进行传递。为什么要强调根本类型呢?上面咱们用类当参数来测试一下:
class A
{public $a = 1;}
function testA($obj)
{$obj->a++;}
$o = new A();
testA($o);
echo $o->a; // 2
在这个例子中,咱们并没有应用 & 标识来表明参数 $obj 是援用类型的,但如果传递的参数是对象的话,那么它默认就是进行的援用传递。如果想让对象也是值传递呢?道歉,在办法参数中是没方法实现的,只能在办法体中应用 clone 形式对对象参数进行克隆。
class A
{public $a = 1;}
function testA($obj)
{
$o = clone $obj;
$o->a++;
}
$o = new A();
testA($o);
echo $o->a; // 1
对于值和援用的问题,能够参考设计模式中原型模式的解说:
PHP 设计模式之原型模式
默认参数
参数是能够有默认值的,这个我想大家都应该很分明了。然而在应用的时候也须要留神,那就是默认参数不要放在后面,否则很容易出错,比方:
function testArgsA($a = 1, $b){echo $a+$b;}
testArgs(); // error
function testArgsB($a = 1, $b = 2){echo $a+$b;}
testArgsB(); // 3
function testArgsC($a, $b = 2){echo $a+$b;}
testArgsC(1); // 3
在简单的函数或者紧急的业务开发中,很有可能一个不小心就会漏写参数,这时候 testArgsA 就会返回谬误了。当然,这种大意类的谬误是咱们应该尽量避免的。
当指定默认值的时候,咱们应该依据参数的类型进行指定,比方字符串就指定为 ”,数字就指定为数字类型。当不确定参数是什么类型时,倡议应用 NULL 做为默认参数。
function testArgsD($a = NULL)
{if ($a) {echo $a;}
}
testArgsD(1);
testArgsD('a');
类型申明
类型申明是在 PHP5 之后增加的性能,就像 java 一样,参数后面加上参数的类型,比方:
function testAssignA(int $a = 0)
{echo $a;}
testAssignA(1);
testAssignA("a"); // error
如果参数的类型不对,间接就会报错。在 PHP7 以前,只反对类、数组和匿名办法的类型申明。在 PHP7 之后,反对所有的一般类型,然而这里要留神的是,只反对一般类型的固定写法。
- Class/interface name
- self
- array
- callable
- bool
- float
- int
- string
固定写法是什么意思呢?
function testAssignB(integer $a = 0) // error
{echo $a;}
也就是说,int 只能写 int,不能应用 integer,bool 也不能应用 boolean。只能是下面列出的类型关键字。
类型申明的益处是什么呢?其实就是 Java 这种动态语言和 PHP 这种动静语言之间的差异。动静类型语言的益处就是变量灵便,不必指定类型,不便疾速开发迭代。但问题也在于灵便,为了灵便,动静语言往往会在比拟或者计算时对变量进行主动类型转换。如果你对变量类型转换的了解不清晰的话,很容易就会呈现各种类型的 BUG。同时,动态类型的语言个别都会有编译打包,而动静类型则是在执行时确定变量类型,所以很少会进行编译打包,相对来说运行效率也就不如 Java 之类的编译后语言了。
对于 PHP 的类型转换问题,能够参考此前的文章:
PHP 中的强制类型转换
Tips 一个小技巧,如果申明了参数类型,是不能传递 NULL 值的,比方:
function testAssignC(string $a = '')
{if ($a) {echo __FUNCTION__ . ':' . $a;}
}
testAssignC(NULL); // TypeError
这时有两种形式能够解决,一是指定默认值 =NULL,二是应用? 操作符:
function testAssignD(string $a = NULL)
{if ($a == NULL) {echo 'null';}
}
testAssignD(NULL); // null
function testAssignE(?string $a)
{if ($a == NULL) {echo 'null';}
}
testAssignE(NULL); // null
可变数量参数
php 中的办法能够接管可变数量的参数,比方:
function testMultiArgsA($a)
{var_dump(func_get_arg(2));
var_dump(func_get_args());
var_dump(func_num_args());
echo $a;
}
testMultiArgsA(1, 2, 3, 4);
咱们只定义了一个参数 $a,然而传进去了四个参数,这时咱们能够应用三个办法来获取所有的参数:
- func_get_arg(int $arg_num),获取参数列表中的某个指定地位的参数
- func_get_args(),获取参数列表
- func_num_args(),获取参数数量
此外,php 还提供了 … 操作符,用于将可变长度的参数定义到一个参数变量中,如:
function testMultiArgsB($a, ...$b)
{var_dump(func_get_arg(2));
var_dump(func_get_args());
var_dump(func_num_args());
echo $a;
var_dump($b); // 除 $a 以外的
}
testMultiArgsB(1, 2, 3, 4);
和参数默认值一样,有多个参数的状况下,…$b 也不要放在后面,这样前面的参数并不会有值,所有的参数都会在 $b 中。不过 PHP 默认曾经帮咱们解决了这个问题,如果 … 参数前面还有参数的话,会间接报错。
利用这个操作符,咱们还能够很不便的解包一些数组或可迭代的对象给办法参数,例如:
function testMultiArgsC($a, $b){echo $a, $b;}
testMultiArgsC(...[1, 2]);
是不是很有意思,那么咱们利用这个个性来合并一个数组会是什么成果呢?
$array1 = [[1],[2],[3]];
$array2 = [4];
$array3 = [[5],[6],[7]];
$result = array_merge(...$array1); // Legal, of course: $result == [1,2,3];
print_r($result);
$result = array_merge($array2, ...$array1); // $result == [4,1,2,3]
print_r($result);
$result = array_merge(...$array1, $array2); // Fatal error: Cannot use positional argument after argument unpacking.
$result = array_merge(...$array1, ...$array3); // Legal! $result == [1,2,3,5,6,7]
print_r($result);
和办法申明参数时一样,在内部应用 … 操作符给办法传递参数时,也不能在 … 前面再有其余参数,所以 array_merge(…$array1, $array2) 的操作会报错。
测试代码:
https://github.com/zhangyue0503/dev-blog/blob/master/php/201911/source/PHP%E6%96%B9%E6%B3%95%E5%8F%82%E6%95%B0%E7%9A%84%E9%82%A3%E7%82%B9%E4%BA%8B%E5%84%BF.php
参考文档:
https://www.php.net/manual/zh/functions.arguments.php
https://www.php.net/manual/zh/functions.arguments.php#121579
https://www.php.net/manual/zh/functions.arguments.php#120580
各自媒体平台均可搜寻【硬核项目经理】