PHP方法参数的那点事儿
在所有的编程语言中,方法或者函数,都可以传递一些参数进来进行业务逻辑的处理或者计算。这没什么可说的,但是在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://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
关注公众号:【硬核项目经理】获取最新文章
添加微信/QQ好友:【xiaoyuezigonggong/149844827】免费得PHP、项目管理学习资料
知乎、公众号、抖音、头条搜索【硬核项目经理】
B站ID:482780532
PHP方法参数的那点事儿的更多相关文章
- 关于PHP的方法参数类型约束
在之前的文章PHP方法参数的那点事儿中,我们讲过关于PHP方法参数的一些小技巧.今天,我们带来的是更加深入的研究一下PHP中方法的参数类型. 在PHP5之后,PHP正式引入了方法参数类型约束.也就是如 ...
- 【.net 深呼吸】细说CodeDom(6):方法参数
本文老周就给大伙伴们介绍一下方法参数代码的生成. 在开始之前,先补充一下上一篇烂文的内容.在上一篇文章中,老周检讨了 MemberAttributes 枚举的用法,老周此前误以为该枚举不能进行按位操作 ...
- Eclipse中自动提示的方法参数都是arg0,arg1的解决方法
Eclipse中自动提示的方法参数都是arg0,arg1,就不能根据参数名来推断参数的含义,非常不方便. 解决方法:Preferences->Java->Installed JREs,发现 ...
- java中方法参数的一些总结(1)
1.问题说明 在C++中,函数调用时有传值调用和传址调用两种方式,但在Java中只有传值调用一种方式.Java中的方法参数为那几种基本数据类型的情况跟C++中一样,传入的只是变量的拷贝. ...
- php课程---Windows.open()方法参数详解
Window.open()方法参数详解 1, 最基本的弹出窗口代码 window.open('page.html'); 2, 经过设置后的弹出窗口 window.open('page.html ...
- Scala正则和抽取器:解析方法参数
在<正则表达式基础知识>中概括了正则表达式的基础知识, 本文讲解如何使用正则表达式解析方法参数,从而可以根据 DAO 自动生成 Service. 在做 Java 项目时,常常要根据 DAO ...
- java方法参数
Java程序设计语言总是采用值调用.也就是说,方法得到的是所有参数的一个拷贝,特别是方法不能修改传递给它的任何参数变量的内容. 基本类型参数 1)X被初始化为percent值的一个拷贝: 2)X被乘以 ...
- 新手容易混乱的String+和StringBuffer,以及Java的方法参数传递方式。
之前在交流群里和猿友们讨论string+和stringbuffer哪个速度快以及Java的方法参数传递的问题,引起了群里猿友的小讨论.最终LZ得出的结果是string+没有stringbuffer快, ...
- block做方法参数时--block的参数传值过程 例1
说明:此例子中方法的调用在此文中是从下到上调用的.(即: 方法五调用方法四: 方法四调用方法三) 方法一:- (void)setCompletionBlockWithSuccess: ...
随机推荐
- Haskell Interactive Development in Emacs
Installation Following haskell-mode. Use MELPA repository: add the following into ~/.emacs (require ...
- java8-stream常用操作(1)
前言 java8的Stream 流式操作,用于对集合进行投影.转换.过滤.排序.去重等,更进一步地说,这些操作能链式串联在一起使用,类似于 SQL 语句,可以大大简化代码.下面我就将平时常用的一些st ...
- Block循环引用详解
前言 在项目中经常用到block,使用不当就很容易因为循环引用而造成内存泄漏.本文分析了block循环引用形成原因以及处理办法,如果有什么不对或者疑问请留言. 什么情况下block会造成循环引用 bl ...
- msfvenom简介
写此文是因为网上资料杂乱,不方便查阅,辣眼睛 测试免杀的时候刚好用到这个功能,顺便写一下(0202年靠msfvenom生成的纯原生payload可以宣告死亡了,如果有查不出来的杀软可以退群了,这也叫杀 ...
- SQL 练习29
查询课程名称为「数学」,且分数低于 60 的学生姓名和分数 SELECT Student.Sname,Course.Cname,SC.score FROM Student,Course,SC WHER ...
- Javaweb学习——request&response
request对象的作用 request是服务器对浏览器访问请求的封装 访问请求参数,通过getParameter()方法获取传递参数的值. 在进行转发请求时,需要把一些参数传递到转发后的页面进行处理 ...
- 【译】JavaScript async / await:好的部分,陷阱和如何使用
async/await提供了一种使用同步样式代码异步访问资源的选项,而不会阻塞主线程.然而,使用它有点棘手.在本文中,我们将从不同的角度探讨async / await,并将展示如何正确有效地使用它们. ...
- Mybatis--级联(一)
级联是resultMap中的配置. 级联分为3种 鉴别器(discrimination):根据某些条件采用具体实现具体实现类级联,如体检表根据性别去区分 一对一:学生和学生证 一对多:班主任和学生. ...
- Oracle数据库 —— DDL
时间:2016-10-5 14:55 逆风的方向更适合飞翔我不怕千万人阻挡只怕自己投降 --------------------------------------- 一.表的创建与管理1.表的基本操 ...
- 用C++实现的有理数(分数)四则混合运算计算器
实现目标 用C++实现下图所示的一个console程序: 其中: 1.加减乘除四种运算符号分别用+.-.*./表示, + 和 - 还分别用于表示正号和负号. 2.分数的分子和分母以符号 / 分隔. 3 ...