函数
0. 说明
全局定义三个函数, 本博文的示例调用时说明略.
function echobr($param = '')
{
echo $param . '<br>';
}
function dumpbr($param = '')
{
var_dump($param);
echo '<br>';
}
function printfpre($param = '')
{
printf('<pre>%s</pre>', print_r($param, true));
}
1. 函数定义
函数定义格式
function 函数名[可选](参数列表[可选]) : 返回值类型[可选] {
函数体...
return 返回值/变量/...[可选]
}
函数定义demo:
<?php
/*
打招呼函数
*/
function sayHello($name) : string {
return $name . ', 你好!';
}
// 调用函数
$str = sayHello();
echobr($str);
2. 函数的类型
函数可分为以下四种类型
自定义函数
- 程序员根据业务需要编写的函数
- 上一点(函数定义)编写的
sayHello()
函数就是自定义函数 示例
<?php
function info($name, $salary) : string {
$info = $name . '本月的薪水是: ' . $salary . '元';
echobr($info);
}
info('zhangsan', 8000);
系统函数
- 由php运行环境提供给程序员使用的函数, 并不需要定义, 拿来即用, 开袋即食. 如:
is_null()
,empty()
,gettype()
,is_array()
等
- 由php运行环境提供给程序员使用的函数, 并不需要定义, 拿来即用, 开袋即食. 如:
可变函数
- 将函数名赋值给一个变量, 可以通过该变量, 调用对应的函数.
- 可变函数的”可变”, 个人理解, 是可以根据不同的条件, 给变量赋予不同的函数名称, 通过该变量调用不同的函数功能.
示例
<?php
function add(int $num1, int $num2) : int {
echobr($num1 + $num2);
}
function minus(int $num1, int $num2) : int {
echobr($num1 - $num2);
}
$funcName = 'add';
$funcName(5, 8);
$funcName = 'minus';
$funcName(20, 10);
匿名函数
- 在PHP中, 匿名函数和闭包同义.
- 匿名函数没有函数名称, 可以把匿名函数的函数定义作为值赋予给变量, 通过变量来调用匿名函数.
- 匿名函数可以作为另一个函数的参数, 也可以被另一个函数当做返回值返回.
示例1:
<?php
// 计算梯形的面积
function calcArea($topLength, $bottomLength, $height, $add) {
// 上底加下底
$totalLength = $add($topLength, $bottomLength);
// 乘以高除以二
$s = $totalLength * $height / 2;
return $s;
}
echobr(calcArea(3, 7, 5, function($a, $b){
return $a + $b;
}));
/*
执行结果:
25
*/
示例2:
// 计算图形面积
function calcArea1($figure)
{
if ($figure === '三角形') {
return function ($bottom, $height) {
// 底乘以高除以二
return $bottom * $height / 2;
};
}
if ($figure === '圆形') {
return function ($r) {
if (!defined('PI')) {
define('PI', 3.14);
}
/* π乘以半径的平方 */
return PI * $r ** 2;
};
}
if ($figure === '矩形') {
return function ($long, $height) {
// 长乘以宽
return $long * $height;
};
}
return '暂无法计算此图形的面积';
}
$func = calcArea1('三角形');
if(gettype($func) === 'object') {
echobr($func(4, 8));
} else {
echobr($func);
}
/*
执行结果:
16
*/
2. 函数的返回值
函数的返回值为单值
- 有
return
的是显式返回;示例略. - 无
return
的, 遇到}
也会返回, 默认返回null
.
无显式返回值函数示例:
// 没有return的函数
function sayHello() {
echobr('hello');
}
$data = sayHello();
dumpbr($data);
/*
运行结果:
hello
NULL
*/
若要返回多值, 返回值有以下四种处理方式
字符串拼接
- 把多个返回值拼接起来, 用一个约定的标记分隔
字符串拼接的使用场景
- 适合处理大量的php+html混写
- 这种返回的格式是用户自定义的, 前端处理非常麻烦
示例
<?php
function userInfo() {
$username = 'zhangsan';
$sex = 'male';
$age = '24';
$salary = 8000;
return $username . ',' . $sex . ',' . $age . ',' . $salary;
}
$userInfo = userInfo();
$userArray = explode(',', $userInfo);
dumpbr($userArray);
/*
执行结果:
array(4) { [0]=> string(8) "zhangsan" [1]=> string(4) "male" [2]=> string(2) "24" [3]=> string(4) "8000" }
*/
返回数组
- 把多个值保存到数组中, 把数组返回.
- 示例
function productList() {
$productList = [
[
'id' => 1,
'cat_id' => 1,
'name' => '华为P40',
'brand' => '华为'
],
[
'id' => 2,
'cat_id' => 1,
'name' => '华为Mate30',
'brand' => '华为'
],
[
'id' => 1,
'cat_id' => 1,
'name' => 'Apple 11 Pro Max',
'brand' => 'Apple'
]
];
return $productList;
}
printf('<pre>%s</pre>', print_r(productList(), true));
/*
允许结果:
Array
(
[0] => Array
(
[id] => 1
[cat_id] => 1
[name] => 华为P40
[brand] => 华为
)
[1] => Array
(
[id] => 2
[cat_id] => 1
[name] => 华为Mate30
[brand] => 华为
)
[2] => Array
(
[id] => 1
[cat_id] => 1
[name] => Apple 11 Pro Max
[brand] => Apple
)
)
*/
- 通过json数据返回
function productList() {
$productList = [
[
'id' => 1,
'cat_id' => 1,
'name' => '华为P40',
'brand' => '华为'
],
[
'id' => 2,
'cat_id' => 1,
'name' => '华为Mate30',
'brand' => '华为'
],
[
'id' => 1,
'cat_id' => 1,
'name' => 'Apple 11 Pro Max',
'brand' => 'Apple'
]
];
return json_encode($productList);
}
printf('<pre>%s</pre>', productList());
/*
运行结果
[{"id":1,"cat_id":1,"name":"\u534e\u4e3aP40","brand":"\u534e\u4e3a"},{"id":2,"cat_id":1,"name":"\u534e\u4e3aMate30","brand":"\u534e\u4e3a"},{"id":1,"cat_id":1,"name":"Apple 11 Pro Max","brand":"Apple"}]
*/
- 通过序列化数据返回
和json数据类似,序列化的结果,也是有一定规则的字符串。
function productList() {
$productList = [
[
'id' => 1,
'cat_id' => 1,
'name' => '华为P40',
'brand' => '华为'
],
[
'id' => 2,
'cat_id' => 1,
'name' => '华为Mate30',
'brand' => '华为'
],
[
'id' => 1,
'cat_id' => 1,
'name' => 'Apple 11 Pro Max',
'brand' => 'Apple'
]
];
return serialize($productList);
}
printf('<pre>%s</pre>', productList());
/*
运行结果:
a:3:{i:0;a:4:{s:2:"id";i:1;s:6:"cat_id";i:1;s:4:"name";s:9:"华为P40";s:5:"brand";s:6:"华为";}i:1;a:4:{s:2:"id";i:2;s:6:"cat_id";i:1;s:4:"name";s:12:"华为Mate30";s:5:"brand";s:6:"华为";}i:2;a:4:{s:2:"id";i:1;s:6:"cat_id";i:1;s:4:"name";s:16:"Apple 11 Pro Max";s:5:"brand";s:5:"Apple";}}
*/
3. 函数的参数
值参数
值参数只传递参数值, 原变量的值保持不变, 不受函数处理的影响
示例:
$name = 'zhangsan';
function sayHello($username) {
$username .= ', 你好';
echobr($username);
}
sayHello($name);
/* 全局变量$name的值还是'zhangsan' */
echobr($name);
/*
运行结果:
zhangsan, 你好
zhangsan
*/
引用参数
- 引用参数相当于传入变量的一个别名, 函数实际处理的还是原变量指向的值. 即原变量的值会因函数的处理而改变.
- 示例:
$num = 0;
// 原值+5;
function addFive(&$num) {
$num += 5;
}
addFive($num);
echobr($num);
/*
运行结果:
5
*/
默认参数
1.和2.都属于必选参数, 默认参数是可选参数, 可选参数必须放在必选参数后面
就是给形参加默认值,调用函数时,若不给该参数传入实参,则该形参就初始化为默认值。
// 循环生成key=value的数组
function createArrayVal($start, $length, $arr = []) {
for($index = 0; $index < $length; $index++) {
$sum = $start + $index;
$arr[$sum] = $sum;
}
return $arr;
}
// 先生成5个数组元素
$arr = createArrayVal(0, 5);
printfpre($arr);
// 再生成3个数组元素
printfpre(5, 3, $arr);
/*
运行结果:
Array
(
[0] => 0
[1] => 1
[2] => 2
[3] => 3
[4] => 4
)
Array
(
[0] => 0
[1] => 1
[2] => 2
[3] => 3
[4] => 4
[5] => 5
[6] => 6
[7] => 7
)
*/
- 剩余参数
个人理解就是,如果一个函数设置了剩余参数,那么传入的参数数量比函数的参数多时,多出的那部分参数当作数组的元素传入到剩余参数中。
function register($first, $second, $third, $fourth, ...$more) {
echobr('第一个挂号的是:' . $first);
echobr('第二个挂号的是:' . $second);
echobr('第三个挂号的是:' . $third);
echobr('第四个挂号的是:' . $fourth);
eochobr('今天加号有' . count($more) . '名病人。它们分别是:');
foreach($more as $key => $item) {
echobr("第{$key + 1}个加号的是:{$item}");
}
}
register('zhangsan', 'lisi', 'wangwu', 'zhaoliu', 'Lucy', 'Lily', 'lilei');
/*
运行结果:
第一个挂号的是:zhangsan
第二个挂号的是:lisi
第三个挂号的是:wangwu
第四个挂号的是:zhaoliu
今天加号有3名病人。它们分别是:
第1个加号的是:Lucy
第2个加号的是:Lily
第3个加号的是:lilei
*/
剩余参数(数组),也可以作为实参传入函数中,这样数组中的元素值,就会按顺序赋值给函数的参数
function register($username, $password, $repassword, $age) {
echobr("注册成功,注册信息为:");
echobr("用户名:{$username}");
echobr("密码:{$password}");
echobr("年龄:{$age}");
}
$user = ['admin', '123456', 25];
register(...$user);
/*
执行结果:
注册成功,注册信息为:
用户名:admin
密码:123456
年龄:25
*/
学习心得
- 个人认为,函数是构成一个可重复调用的功能的最小单位。复杂的功能则需要多个函数协同工作完成。
- 函数的学习围绕组成函数的部分展开。
- 函数的类型,根据函数的提供方划分,可以划分为自定义函数(程序员自己写的函数)和系统函数(PHP运行环境提供的,开袋即食的函数);根据是否拥有函数名划分,可分为命名函数和匿名函数。某个变量,可以指向不同的匿名函数,这样的变量就变成了可变函数。
- 函数的返回值,函数的返回值都是单值返回。如果要返回多个值,都是想办法把多个值变成可以解析的某种单值数据结构返回。最简单的办法,是使用某个约定好的字符串分隔符把多个值连接。也可以使用数组/对象等复合数据结构的数据返回。在web前后端交互中,一般采用json格式或序列化的数据格式返回。这两种方式,本质上也是返回使用特定的字符串连接多个数据值形成的字符串,但是这两种方法是公认的经过规范化使用的。
- 函数的参数,函数的参数就是传递给函数处理的“原材料”。根据传递方式的不同,可以分为值参数和引用参数,值参数不会改变原变量的值,而引用参数则会改变原变量的值。当参数的某个值在实际使用中频繁出现时,可以把这个值设置为该参数的默认值,该参数就变成了默认参数,在函数调用时就可以省略对默认参数的传值,函数会使用默认参数的默认值参与函数逻辑运算。当函数参数是数量不定的多个相同意义的变量值时,可以考虑使用剩余函数来设置函数参数,个人感觉这不是必须的,因为剩余函数也可以用默认值是空数组的默认参数来实现,区别在于剩余函数会自动把多出来的变量转成数组,而默认参数则需要手动创建参数数组才能传参。