PHP-3: 函数编程基础
1. 语法
函数是实现代码复用的重要方式,在所有编程语言中均如此
function 函数名称(类型: 参数列表): 返回值类型
{
// 函数体
return 返回值;
}
| 序号 | 名称 | 描述 |
|---|---|---|
| 1 | function |
声明函数 |
| 2 | 函数名称 |
符合 PHP 标识符命名规范,不区分大小写 |
| 2 | 参数列表 |
零个或多个接收外部传入到函数的变量 |
| 2 | {... |
创建出一个封闭的函数作用域 |
| 2 | 函数体 |
由零个可多个合法的 PHP 语句组成 |
| 2 | return 值 |
将执行结果返回函数调用者[可选] |
| 2 | ...} |
函数执行结束,如果没有return,则返回null |
示例代码: demo1.php
# 函数语法
// 声明: function 关键字
function func1(int $a, int $b) : int
{
return $a + $b;
}
// 调用: 按名调用
echo func1(10, 20);
2. 类型
| 序号 | 类型 | 语法 | 描述 |
|---|---|---|---|
| 1 | 自定义函数 | function getName(){...} |
用户根据业务需求创建 |
| 2 | 系统函数 | substr(), count()... |
也叫预定义函数,不必声明直接调用 |
| 3 | 可变函数 | $funcName(); |
函数名使用变量表示 |
| 4 | 匿名函数 | $f = function (){...} |
也叫"闭包"或"函数表达式",常用做回调处理 |
示例代码: demo2.php
# 函数类型
// 1. 自定义函数
function getPrice(float $money, float $discount): float
{
return $money * $discount;
}
echo '实付金额 = ' . getPrice(5000, 0.8);
echo '<hr>';
// 2. 系统函数
$str = '钟南山团队入围2020年度国家科技奖提名';
// 仅获取前5个中文字符
echo mb_substr($str, 0, 5);
echo '<hr>';
// 3. 可变函数
// 仍以前面已声明的函数: getPrice()为例
$funcName = 'getPrice';
// 被调用的函数名称保存到一个变量中
// 这个功能很实现,在后面课程中会看到更多应用
echo '实付金额 = ' . $funcName(8000, 0.7);
echo '<hr>';
// 3. 匿名函数
$f = function (float $money, int $num): float {
return $money * $num;
};
echo '实付金额 = ' . $f(100, 20);
echo '<br>';
// 匿名函数也叫闭包,可以继承父作用域中的变量
$discount = 0.8;
// $discount 是父作用域中的变量,这个父作用域可以是全局, 也可以是父函数
// 父作用域是全局
$getAmount = function (float $money, int $num) use ($discount): float {
$amount = $money * $num;
return $amount > 2000 ? $amount * $discount : $amount;
};
echo '实付金额 = ' . $getAmount(120, 20);
echo '<br>';
// 父作用域是函数
$f = function (float $discount) {
$getAmount = function (float $money, int $num) use ($discount): float {
$amount = $money * $num;
return $amount > 2000 ? $amount * $discount : $amount;
};
return $getAmount;
};
echo '实付金额 = ' . $f($discount)(120, 20);
3. 返回值
- 函数必须要有返回值
- 函数必须是遵守单值返回原则
| 序号 | 场景 | 描述 |
|---|---|---|
| 1 | return |
可以返回任何类型的值,包括函数类型 |
| 2 | 无return |
遇到}也会返回, 默认返回null |
- 如果需要返回多个值,可以通过以下手段
| 序号 | 返回值类型 | 描述 |
|---|---|---|
| 1 | string |
字符串拼接 |
| 2 | array |
数组 |
| 3 | json |
JSON 字符串 |
| 4 | serialize |
序列化字符串 |
json 和序列化,使用时需要进行解码操作
示例代码: demo3.php
<?php
# 函数返回值
// 单值返回,前面已经有了许多案例,重点放在多值返回上
// 1. 通过拼装字符串实现
function demo1(): string
{
$status = 1;
$message = '成功';
return $status . ', ' . $message;
}
echo demo1();
// 字符串拼装返回非常适合处理大量变量与html标签的混写
// 字符串拼装返回多值有许多限制,并且对返回值的解析处理非常麻烦
echo '<hr>';
// 2. 通过数组返回多值
function demo2(): array
{
return ['status' => 1, 'message' => '验证成功'];
}
echo demo2()['status'] === 1 ? demo2()['message'] : '验证失败';
// 返回值如果仍在php程序中处理,这样做很方便
// 开发中, 通常返回值都是要交给前端处理的,转为JSON格式更方便
echo '<hr>';
// 3. 通过JSON格式返回多值
// json是一种通用的,轻量级数据表示格式,使用javascript对象字面量表示数据
// 几乎所有编程程序,都支持定义和解析json格式的数据,请放心使用
// 当前后端时行数据交互时, json格式几乎成了除字符串之外的唯一选择
// json本质上仍是字符串, 只不过具有一些特殊格式,需要进行解析罢了
function demo3(): string
{
// json_encode(): json编码函数,将数据编码为json格式字符串返回
return json_encode(['status' => 1, 'message' => '验证成功']);
}
// json_decode():json解码函数, 解析json格式字符串,默认返回对象,true表示返回数组
$data = json_decode(demo3(), true);
echo '<pre>' . print_r($data, true) . '</pre>';
echo '<hr>';
// 4. 通过序列化返回多值
// 序列化可以将程序中的变量/数据做持久化保存,可以进行传输,保存到文件中等
// 与json一样, 序列化也有序列化与反序列二种操作
function demo4(): string
{
return serialize(['status' => 1, 'message' => '验证成功']);
}
// 查看序列化的格式化字符串
echo demo4(), '<br>';
// 反序列化
$data = unserialize(demo4());
echo '<pre>' . print_r($data, true) . '</pre>';
echo '<hr>';
// 5. 返回null
function demo5(int $n): ?int
{
if ($n < 10) return $n * 2;
// 如果允许返回null空, 必须显式的指出来,否则报错
return null;
// 可以简写
// return ($n < 10) ? $n * 2 : null;
}
echo demo5(15);
4. 参数
- 调用者可以通过参数将数据传递到函数中
- 参数是以逗号分隔的表达式列表
- 参数按照从左到右的顺序求值
参数类型
| 序号 | 类型 | 描述 |
|---|---|---|
| 1 | 值参数 | 默认传参方式 |
| 2 | 引用参数 | 改变原始调用参数值 |
| 3 | 默认参数 | 调用时允许省略的参数 |
| 4 | 剩余参数 | 调用参数数量不确定 |
示例代码: demo4.php
# 函数参数
// 1. 值参数: 默认
function demo1(float $arg): float
{
return $arg *= 2;
}
$value = 100;
echo demo1($value), '<br>';
echo $value, '<br>';
echo '<hr>';
// 2. 引用参数
// 引用传参: 参数前添加地址引用符
function demo2(int &$arg): float
{
// 函数内部更新了调用参数,则直接影响到原值
return $arg *= 2;
}
$value = 100;
echo demo2($value), '<br>';
echo $value, '<br>';
echo '<hr>';
// 3. 默认参数
// 参数列表中,允许有必选参数和默认参数二大类, 默认参数必须排列在必选参数的后面
// 默认参数决定了函数的默认行为,如果函数默认行为满足要求,显然不传参调用更方便
// 默认参数也允许用户根据自身需求,传入自定义参数,对函数的行为进行干预
// 注意, 执行正确返回数值,错误返回字符串类型, 所以不要限制函数的返回类型
function demo3(float $a, float $b, string $opt = '+')
{
$res = 0;
switch ($opt) {
case '+':
$res = "$a + $b = " . ($a + $b);
break;
case '-':
$res = "$a - $b = " . ($a - $b);
break;
case '*':
$res = "$a * $b = " . ($a * $b);
break;
case '/':
$res = "$a / $b = " . ($a / $b);
break;
default:
$res = '非法操作符';
}
return $res;
}
// 如果用户不传第三个参数,则使用默认参数,即默认执行:+ 加法
echo demo3(10, 20), '<br>';
// 传入用户自定义操作, 如*, 乘法
echo demo3(10, 20, '*'), '<br>';
// 传入非法数据: #
echo demo3(10, 20, '#'), '<br>';
echo '<hr>';
// 4. 剩余参数
function demo4(float $a, float $b, float $c): float
{
return $a + $b + $c;
}
// 计算三数之和
echo demo4(1, 2, 3), '<br>';
// 如果计算五数之和,甚至更多数的求和,难道要这样一直写下去呢?
// 其实函数的参数列表中的参数,只是占位符罢了,可以为空的
// 函数内部可以通过其它方式来获取到调用参数的
// php5.5之前,可以用以下三个函数来获取调用参数
// func_num_args(),func_get_arg(), func_get_args()
// 现在已经用不到它们了,我们可以使用一种更加优雅的方式来获取:剩余参数
// 剩余参数的概念与语法与JavaScript中是一样的, 熟悉js的同学一定不陌生
// 计算任意个数据之和
function sum(float ...$args): float
{
print_r($args);
echo '<br>';
return array_sum($args);
}
$arr = [2, 3, 4, 6, 88, 23, 1, 24];
// ...: 剩余参数展开与收集操作符
// 调用时,执行展开操作, 传参时执行收集操作
echo sum(...$arr);
5. 回调函数
| 语法 | 类型 | 执行方式 | 应用场景 |
|---|---|---|---|
| 匿名函数 | 闭包Closure |
异步 | 函数参数 |
异步执行,是指当前函数的执行并不会中断当前程序的执行流程
示例代码: demo5.php
# 回调函数
$data = range(1, 100);
// print_r($data);
// 使用回调,可以异步的处理海量数据,并不中断当前程序
$arr1 = array_map(function (int $item) {
if ($item % 2 === 0) return $item;
}, $data);
echo '<hr>';
print_r($arr1);
// 过滤掉空值
$arr2 = array_filter($arr1, function ($item) {
return $item;
});
echo '<hr>';
print_r($arr2);
6. 命名空间
- 使用目录来整理文档, 允许将同名文档,存储在不同的目录下面即可
- 不同目录下的同名文件,访问时必须带上的它的目录名称,以未区别
- 命名空间采用类似的思想,同名函数,只要声明在不同空间中即可
- 同样, 访问这些函数时, 也需要带上它的命名空间才可以
示例代码: demo6.php
# 函数命名空间
// function demo1(): string
// {
// return __FUNCTION__;
// }
// function demo1(): string
// {
// return __FUNCTION__;
// }
// 报函数重复命名错误
// 可以在不同命名空间中创建同名函数
namespace ns1 {
function demo1(): string
{
return __FUNCTION__;
}
}
namespace ns2 {
function demo1(): string
{
return __FUNCTION__;
}
}
namespace {
// 带有空间的函数,调用时需要带上它的空间名称
echo \ns1\demo1();
echo '<hr>';
echo \ns2\demo1();
}