Correcting teacher:天蓬老师
Correction status:qualified
Teacher's comments:
函数的语法
function 函数名(类型限定 参数列表): 返回值类型
{
函数体
return 返回值;
}
// 1. 命名函数
// 自动提升到脚本的顶部,在全局的任何地方都可以调用到
function demo1()
{
return 'Hello';
}
// 按名访问
echo demo1(), '<br>';
// 2. 匿名函数
$demo2 = function () {
return 'word';
};
echo $demo2();
// 1. 必选参数
function demo1(string $name): string
{
return "hello $name ";
}
echo demo1('TJ'), '<br>';
// 将标量(单值)自动转换为字符串
echo demo1(123), '<br>';
echo demo1(true), '<br>';
// echo demo1([]), '<br>';
// echo demo1(new class
// {
// }), '<br>';
// echo demo1(); //错误
// 2. 可选参数
function demo2(string $email, string $name = 'TJ'): string
{
return "hello $name ,$email";
}
// echo demo2(), '<br>';
echo demo2('T。。。'), '<br>';
// 当有多个参数时,可选参数必须放在后面
// 必填参数是必须要求有的,如果将可选参数放到首位会有逻辑冲突,既要求必须填,还允许不填。
// 3. 不定参数
function demo3(float $a, float $b, float $c): float
{
return $a + $b + $c;
}
echo demo3(1, 2, 3), '<br>';
//如果有更多的参数,怎么才能更高级和优雅
function demo4()
{
// 通过函数中内置的三个函数获取到参数的全部信息
// 1. 参数个数
$n = func_num_args();
// 2. 参数组成的数组
// func_get_args()
$args = '[' . implode(',', func_get_args()) . ']';
// 3.获取某一个参数
// $arg = func_get_args()[1];
//等价与
$arg = func_get_arg(1);
printf('参数数量:%d<br> 参数数组: %s <br> 第二个参数: %s <br>', $n, $args, $arg);
// 求和
echo '和:', array_sum(func_get_args());
}
demo4(1, 2, 3);
//js中有 ...rest 语法,剩余参数
function demo5(...$args)
{
// print_r($args);
$n = count($args);
$arg = $args[1];
printf('参数数量:%d<br> 参数数组: [%s] <br> 第二个参数: %s <br>', $n, implode(',', $args), $arg);
}
demo5(1, 2, 3, 4);
//实战: 数据表查询
echo '<hr>';
function connect(...$args)
{
print_r($args);
return new PDO($args[0], $args[1], $args[2]);
}
//
$pdo = connect('mysql:dbname=mysql', 'root', 'root');
if ($pdo) echo '<h3>连接成功</h3>';
// 4. 引用参数
echo '<hr>';
//js函数只支持值传递
// php支持“值传递”和“引用传递”
//默认是值传递
//引用传递(引用传参)
//在函数内部对参数的任何更新都会映射到外部的参数中
//在函数的参数前面使用:&
$name = 'TJ';
function demo6(string &$name)
{
$name = '新参数';
}
echo "\$name = $name <br>";
demo6($name);
echo "\$name = $name <br>";
// 函数值允许有一个返回值
// 原则:单值返回
// 返回多值怎么办?
// 1. 数组
function demo1(): array
{
return ['status' => 1, 'message' => '验证成功'];
}
$res = demo1();
var_dump($res);
echo '<br>';
echo $res['status'] === 1 ? $res['message'] : '验证失败', '<br>';
// 2. 对象
function demo2(): object
{
// 匿名类
return new class()
{
public $name = 'admin';
public $email = 'admin@php.cn';
};
}
$user = demo2();
// var_dump($user);
printf('name = %s <br>email = %s<hr>', $user->name, $user->email);
// 3. 序列化的字符串
// 3.1 php 内置的序列号函数
// 如果有一些数据需要进行网络传输或者保存到文件或者数据表中的时候需要用到他
// 如果这个序列化的数据只在php程序中使用,应该使用php内置的方法
function demo3(): string
{
return serialize(['status' => 1, 'message' => '验证成功']);
}
$str = demo3();
echo $str;
// file_put_contents('file.txt', $str . "\\n ", FILE_APPEND | LOCK_EX);
$arr = unserialize($str);
echo '<br>';
var_dump($arr);
echo '<br>';
// 3.2 转为json格式的字符串
// 这样就可以与其它编程语言进行数据交换,例如与js,java,python
function demo4(): string
{
// return json_encode(['status' => 1, 'message' => '验证成功'], JSON_UNESCAPED_UNICODE);
// 等效于
return json_encode(['status' => 1, 'message' => '验证成功'], 256);
// 还可以用320:JSON_UNESCAPED_SLASHES + JSON_UNESCAPED_UNICODE => 64 + 256: 不编码,不转义
//448=64+128+256 64即不转换\ 128 不转换\n \r \t之类的空白 256中文输出
}
$str = demo4();
echo ' json_encode => ', $str, '<br>';
// 常量的整数表示
// JSON_HEX_TAG => 1
// JSON_HEX_AMP => 2
// JSON_HEX_APOS => 4
// JSON_HEX_QUOT => 8
// JSON_FORCE_OBJECT => 16
// JSON_NUMERIC_CHECK => 32
// JSON_UNESCAPED_SLASHES => 64
// JSON_PRETTY_PRINT => 128
// JSON_UNESCAPED_UNICODE => 256
// JSON_PARTIAL_OUTPUT_ON_ERROR => 512
// JSON_PRESERVE_ZERO_FRACTION => 1024
// 如果当前脚本接收一个前端或者其它接口发送过来的json 格式的数据,可以进行解析
// 解析的目的是将外部的json还原成php能够处理的数据类型
$res = json_decode($str);
var_dump($res);
echo '<br>';
//默认将外部的json解析为object对象类型
printf('status = %d message = %s<hr>', $res->status, $res->message);
// 如果不喜欢对象方式访问,也可以使用数组方式
// json_decode()传入第二个参数:true;
$res = json_decode($str, true);
var_dump($res);
echo '<br>';
printf('status = %d message = %s<hr>', $res['status'], $res['message']);
// js:函数作用域,块作用域(es6+)
// php:函数作用域
//声明在函数外部的成员,默认就是全局成员
$name = 'TJ';
$email = 'TJ@tj.com';
function demo1(): string
{
// 函数作用域:只有调用它的时候才会创建
$res = '';
// 如果想在函数内部访问全局 / 外部的成员
// 有两种方式可以在函数内部访问外部成员
// 1. global
global $name;
$res = 'name =>' . $name . '<br>';
// 2. $GLOBALS 超全局数组不受作用域限制,声明的所有全局变量都存在这个数组中
$res .= 'email =>' . $GLOBALS['email'] . '<br>';
// 函数内部声明的变量:外部不可见
$salary = 9988;
$res .= 'salary =>' . $salary . '<br>';
return $res;
}
echo demo1();
// 2. 闭包:匿名函数
// 可以访问函数外部的自由变量
echo '<hr>';
$demo2 = function () use ($name, $email) {
return sprintf('name = %s<br> email = %s <br>', $name, $email);
};
echo $demo2();
//闭包支持引用传参(经常用,
echo '<hr>';
echo '当前:name = ' . $name . '<br>';
$demo3 = function ($myname) use (&$name) {
$name = $myname;
};
echo $demo3('TM TJ');
echo '现在:name = ' . $name . '<br>';
// use 禁止使用已下三种参数
// 1. 超全局不能用: $_GET
// 2. $this
// 3. 与当前参数重名不能用
// 闭包经常用作函数的返回值
function demo4($site)
{
//返回一个函数,闭包的最佳使用场景
return function ($color) use ($site) {
return sprintf('<h3 style="color:%s">%s</h3>', $color, $site);
};
};
// var_dump(demo4('php'));
echo '<hr>';
$cl = demo4('php');
echo $cl('red');
// 高阶函数 : 柯里化
echo '<hr>';
echo demo4('php.cn')('red');
// 回调执行
function demo1(string $name): string
{
return "Hello $name !";
}
// 传统方式
echo demo1('TJ'), '<hr>';
// php 单线程,同步执行,如果遇到耗时函数会发生阻塞,应该将它改为异步回调执行
//call_user_func(函数,参数列表)
echo call_user_func('demo1', 'callBack'), '<hr>';
//call_user_func_array(函数,参数列表)
echo call_user_func_array('demo1', ['callBackToo']), '<hr>';
$sql = 'SELECT * FROM `db` LIMIT 1';
$demo2 = function ($dsn, $username, $password) use ($sql) {
$pdo = new PDO($dsn, $username, $password);
$stmt = $pdo->prepare($sql);
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
};
$res = call_user_func_array($demo2, ['mysql:dbname=mysql', 'root', 'root']);
print_r($res);
// 这两个函数还可以异步的调用对象方法
class User
{
// 实例方法
public function hello(string $name): string
{
return "hello $name !";
}
//静态方法:;类调用
public static function say(string $site): string
{
return "欢迎来 $site !";
}
}
// 实例方法
$res = call_user_func_array([new User, 'hello'], ['TJ']);
echo $res, '<br>';
// 静态方法
// $res = call_user_func_array(['User', 'say'], ['o-o']);
// 等价于
$res = call_user_func_array('User::say', ['o-o']);
echo $res, '<br>';
// 静态变量
function demo1()
{
//静态话的变量不会消除
//函数中的静态变量不会随着函数调用解释而消失。自动进入下一次的函数调用中
// 可以实现在函数的多次调用过程中: 共享数据 / 数据通信
static $i = 1;
echo $i, '<br>';
$i++;
}
echo demo1();
echo demo1();
echo demo1();
echo demo1();
注意:call_user_func_array()
会用的比较多
个人感觉,静态方法调用$res = call_user_func_array('类::方法', ['参数']);
比$res = call_user_func_array(['类', '方法'], ['参数']);
好理解。
总结:
为了和实例方法调用一起记忆还是统一比较好记。
实列调用:$res = call_user_func_array([new 类, '方法'], ['参数']);
静态调用:$res = call_user_func_array(['类', '方法'], ['参数']);