PHP的函数应用:
关于函数的定义:
(我觉得这个需要具体的定义一下,于是就写在了这里)
函数是:一个被命名的、独立的代码段,它执行特定的任务,并可能给调用它的程序返回一个值。
每个函数都有唯一的名称,函数可以在没有其他程序的干预下独立的完成其任务,函数执行特定的任务,函数可以将一个返回值返回给调用它的程序。
PHP中函数的声明:
在PHP中,自己声明的函数执行效率一般没有系统自带的函数高,但是两种函数在程序中的调用方式是没有区别的。
在PHP中声明一个自定义的函数可以使用以下的语法格式:
function 函数名 ([参数1,参数2,......参数n]) //函数头,和C语言中的函数其实没多少的区别,只是定义方式不一样,使用一个叫做function的函数而已。
{
函数体; //任何有效的PHP的代码都可以作为函数体使用
return 返回值; //可以从任何函数中返回一个值
}
在PHP中因为不能使用函数重载,所以是不能定义重名的函数的,同时也不能和系统函数重名,同时对函数的命名也要遵守变量命名的规范。
在声明函数的时候,后面的括号是必须有的,在括号中表明的是一组可以接受的参数列表,参数就是声明的变量,然后在调用函数的时候传递给它值(此处@C语言中的实参和形参,其实真的就差不多,毕竟PHP的内核就是C语言)。
参数列表可以没有,也可以有多个使用逗号隔开的值
在return后面可以加上一个表达式,直接会返回这个表达式的值。
PHP中函数的调用:
关于函数的调用,在PHP中和在C语言中其实是差不多的。只要在需要使用函数的位置使用函数名称和参数列表进行调用即可。
如果函数设置有参数列表,还可以通过在函数名后面的小括号传入对应的值给参数,在函数体中使用参数来改变函数内部代码的执行行为。
只要声明的函数在脚本中可见,就可以通过函数名在脚本的任意位置调用。**在PHP中可以在函数的声明之后调用,也可以在函数的声明之前调用。**这一点是比较关键的。
在函数中,在定义函数时,后面的括号中是形参,而在调用函数时,在括号中的是实参。形参可以被看成是一个占位符,只会在函数被调用的时候接收传入进来的数据,所以才是形式意义上的参数。而实参则是在函数被调用的时候实实在在包含了数据,会被内部的代码使用,所以叫做实际参数,简称为实参。
**实参和形参的传递需要按顺序对应传递数据。**相对的,如果一开始就没有设置参数列表,那么这个定义函数就不能根据使用者的意图进行动态变化了。
只要设置有返回值,当函数执行完毕之后,就会把return后面的值返回到调用函数的位置处,这样就可以把函数的名称当成函数的返回值使用。
PHP中的参数:
关于PHP中的参数列表,这是由0个1个或是多个参数组成的,每个参数是一个表达式,使用逗号来进行分隔,对于有参函数,在PHP脚本程序中和被调函数之间有数据传递关系。
函数的返回值:
关于函数的返回值,如果函数没有返回值,就只能算一个执行过程。由于变量作用域的差异,调用函数的脚本程序不能直接使用函数体里面的信息,所以需要通过return语句向调用者传递语句。
return语句一般来说有:1、可以向函数调用者返回函数体中任意确认的值 2、将程序控制权返回到调用者的作用域,及退出函数,如果在函数体中执行了return函数,它后面的语句是不会被执行的。
因此,对于return语句其实有一个用法就是把所有的改变的语句全部都放在一个变量之中,然后一次性使用return语句返回这个变量,就可以直接改变输出的结果。
基于上面说的,执行了return语句之后,它后面的语句就不会被执行了,因此无法使用多个return语句返还多个数据,要同时返还多个数据可以使用数组结构来进行。在使用return语句返回这个数组之后就可以正常的使用这个数组。
从PHP7开始,增加了对返回类型的声明,可以指明函数返回值的类型
function 函数名 ([参数1,参数2...]):类型
{
函数体;
return 返回值;
}
这其中有一个新的类型——void,选择了这个类型之后,返回值会变为null类型,在使用void的时候,要么就省去return语句,要么就使用一个空的return语句(对void函数来说,null不是一个合法的返回值),就不允许返回其他类型的数据。
(试图去获得一个void方法的返回值会得到null,并且不会产生警告)。
类型声明:
因为PHP是弱类型的编程语言,所以在老的版本中是不允许在声明变量时加上类型限制的,但是在PHP5中可以在函数的形参中加上类型声明了,一但声明之后,就会对不符合预期的参数进行强制的类型转换。
而从PHP7中开始,函数中的形参类型声明可以是标量,也就是除去,类名、接口,array、callable以外还可以使用string、int、float、bool类型了。
eg:
function a(int $a,int $b){
函数体;
}
加上相应的类型语句就可以实现相应的变量声明了,就是会强制性的把变量以相应的类型传入进去。类似于一个强制类型转换。
特别的严格模式:
在PHP7中新增加了一个declare指令: strict_types,该指令必须要放在文件的顶部,这意味这严格声明变量是基于文件可配的,这个指令不仅影响参数的类型声明,还影响到函数的返回声明。
使用的方法如下:
<?php
declare(strict_types=1); //必须要顶格。
中间函数省略;
?>
在这个严格模式下,如果传入的参数或是返回值与预期的值不符(返回值还是要用之前的那种方式特殊设定),会触发TypeError的致命错误(Fatal error)终止程序运行,同时是不会进行强制类型转换的。
PHP中的变量类型:
1、局部变量:
也叫做内部变量,是在函数内部声明的变量,其作用域仅限于函数内部,离开该函数后再使用这种函数是非法的。同样的,为声明函数所设置的变量也是局部变量,这个的作用域同样是只限制于函数中。在函数调用完毕之后,函数内部的变量都会被释放。
2、全局变量:
也叫做外部变量,是在函数的外部定义的,作用域是从变量的定义处开始,一直到程序文件的末尾。和其他编程语言不同的是,PHP中的全局变量不是自动设置为可以使用的。由于函数可以视为独立的程序片段,所以局部变量会覆盖全局变量的能见度,因此要必须使用global关键字来定义目标变量(不能在定义目标变量的同时对目标函数。
eg:
<?php
function demo(){
global $one,$two; //在函数内部使用global关键字定义一个全局的变量。
后续函数省略;
}
要达成同样的效果,还可以使用特殊的PHP自定义的 G L O B A L S 数 组 。 之 前 的 例 子 同 样 可 以 写 成 使 用 GLOBALS数组。之前的例子同样可以写成使用 GLOBALS数组。之前的例子同样可以写成使用GLOBALS来替代global关键字。
<?php
$one=200;
$two=100;
function demo(){
$GLOBALS['two']=$GLOBALS['one']+$GLOBALS['two'];
}
在这个函数之中,每一个变量都是一个元素,键名对应的是变量名,值对应变量的内容,$GLOBALS之所以在全局范围内存在,是因为这是一个超全局的变量。
3、静态变量:
局部变量,从存储的方式上面可以区分为静态和动态两种存储类型。如果不是专门的声明为static(静态)类型,默认的都是动态的分配存储空间的(这很好理解,毕竟不管是什么电脑,内部的存储都是有上限的,所以会自动的减少对内存的占用,之前的unset()函数也是这样的)。
相对来说,如果希望可以在函数执行之后,其内部的变量依然保存在内存中,就要使用静态变量。
在函数执行完毕偶,静态变量并不会消失,而是在所有对该函数的调用之间共享,即是在函数再次执行时,静态变量将接续前次的结果继续运算,并且仅在脚本的执行期间,函数第一次被调用的时候被初始化。
使用关键字static来声明一个静态的变量:
<?php
function test(){
static $a=0; //定义了一个静态变量A,同时赋初值为A。
}
每次函数的执行,静态变量都会从自己的内存空间中获取上一次的储存结果,并以此为初值进行接下来的运算。
PHP中各种函数的形式:
1、常规参数的函数:
这种函数,就是实参和形参应该有个数相等,类型一致。同时,在调用函数时传递的参数个数和顺序都必须一致(就是说假设有三个不同类型的参数需要传递,不只是顺序要相同,就连类型也必须时一模一样的)
常规参数的函数:
string chr(int ascii)
2、伪类型的函数:
因为PHP是弱类型的语言,所以在声明函数的时候如果不指定类型,每个参数都可以为其传递任意类型的值。
关于伪类型,之前的笔记中有写,我搬过来以自查:
常用的伪类型有如下几种:
1、mixed:说明一个函数可以接受多种不同的类型(但并不是所有的)。
2、number:说明一个函数可以是integer或者是float。
3、callback:有些函数接受用户自定义的函数作为一个参数,callback函数可以是一个函数,一个对象的方法,包括静态类的方法。
1:在声明函数时,如果函数能够接受多种不同但并不必须是所有类型的值,就可以使用mixed标记这个参数的类型。
2:如果说明一个参数可以是integer或是float,就可以使用number来标记参数。
除了参数,对于返回值也可以根据参数类型的不同,返回不同类型的值
伪类型参数的函数格式:
mixed funName(mixed $args)
number funName(number $args)
3、引用参数的函数:
格式:
void funName(array &arg)
函数的参数也属于局部变量,因此,即使是在函数的内部改变参数的值,它也不会改变函数外部的值。(函数为子程序,调用函数的程序可以称为父程序。)
这一部分的内容基本上就可以理解为是C语言中的指针的运用。
只要在函数的定义中,在参数的前面预先加上一个符号&,就可以实现C语言中的"一重指针",这也是引用参数的最基本的含义。
//格式如下:
<?php
function demo(&$a){
函数体;
}
这样就相当于是使用了一个指针。
一旦使用了&这个字符,在传入参数的时候就必须是传入一个变量而不能传入一个值
4、默认参数的函数:
格式:
mixed funName(string name [,string value[,int value]]) //使用[]来描述的参数
在定义函数时声明了函数,而在调用函数的时候却没有指定参数或是少指定了参数,会使得出现缺少参数的警告。
基于以上的特性,在PHP中,可以使用默认函数,也就是提前给函数设定一个默认值,如果没有传入参数的话,直接使用这个默认值。
其中,默认值必须时常量表达式,不能是变量、类成员或者是函数调用。
同时PHP允许使用数组和特殊类型的NULL作为默认参数。
默认参数函数的使用方法:
<?php
function demo($name="张三",$age=20,$sex="男"){
函数体部分省略;
}
注:如果只给其中的几个参数赋了初值的话,就必须把所有赋了初值的函数放在没有赋初值的参数的右边,否则该函数将不能正常运行。
5、可变个数参数函数:
格式说明一般如下:
mixed funName(string arg1 [,string ...] )
相较于之前的默认参数函数,可变个数参数一般适用于实参个数多于形参的时候。如果在函数中用不到多传入的参数则没有意义。通常,用户在定义函数的时候,设置的参数数量是有限的。如果希望可以接受任意数量的参数,就要使用PHP系统中的func_get_args()函数,如下:
<?php
function more_args(){
$args=fun_get_args(); //将所有传递给脚本函数的参数当成是一个数组返回。
for($i=0;$i<count($args);$i++){
echo "第".$i."个参数是".$args[$i]."</br>";
}
}
还可以使用func_num_args()函数返回参数的总数,使用func_get_args()函数接收一个数字参数,返回指定的参数
eg:
<?php
function more_arg(){
for($i=0;$i<func_num_args();$i++){ //其中的函数的意思是返回函数中参数的个数,是一个数字。
echo "第".$i."个参数是".func_get_arg($i)."</br>"; //函数的意思是返回指定位置的参数的值
}
}
从PHP5.6以后,可以不使用之前的函数,而是使用“…”运算符来实现变长参数函数,将传入的形参改变为数组。
<?php
function sum(...$ints){
}
//或者是:
function sum(int ...$ints):{
}
//这样调用都是可以的。
同时,在调用函数的时候,还可以使用…运算符将数组和可遍历的对象展开为函数参数,代码如下所示:
<?php
function add($a,$b,$c,$d) {
return $a+$b+$c+$d;
}
$operators=[2,3,4];
echo add(1, ...$operators);
(书上写得太抽象了,我简单解释一下,其实就是在使用了…运算符之后,就可以把数组中的值按顺序传递给函数中的每一个参数,就比如上面的代码中,其实就是把1赋给$a,然后把2,3,4分别赋值给b,c,d)
在过去,如果在调用一个用户定义的函数时,提供的参数不足,就会产生一个警告(warning)但是在PHP7以后的版本中,警告被升格为了一个错误异常(Error exception),且该变更仅对用户定义的函数有效,对内置的函数是没有效果的。
类型在PHP中也是允许为空,当启用这个特性的时候,传入的参数或者函数返回的结果要么是给定的类型,要么就是null。可以在类型前面加上一个(?)问号来使之成为可空的通配符。
回调函数:
关于回调函数的格式:
mixed funName(callback arg) //其中callback是伪类型,详情可以去看1-PHP
简单概述一下,所谓的回调函数其实就是在函数中使用函数,要实现这个目的,首先要介绍一个东西:
只要在函数的格式中出现了callback伪类型,这个函数就是一个回调函数
PHP中的变量函数:
变量函数也称为可变函数,其实就是一种对函数的引用方式:
如果在一个变量后有圆括号,PHP将寻找与变量的值同名的函数,并且将尝试执行它。
**将上面的话用人话来说一遍:**其实就是可以将一个函数重命名为一个变量,举个例子,当定义了一个函数:test()时,可以使用赋值语句将函数名赋给一个变量 d e m o , 也 就 是 : demo,也就是: demo,也就是:demo=“test”,当使用echo语句进行输出的时候,会直接打印出一个"test"字符串,但是当在变量后面加上一个括号$demo(),同时传入相应的参数时,就可以当作函数调用。
基于以上的原理,可以将函数以参数的形式传入另一个函数中,在另一个函数的函数体中为变量添加括号来当作函数调用。
eg:
<?php
function one($a,$b){
return $a+$b;
} //此处声明一个函数名为one的函数。
$result="one"; //将函数名one赋给变量$result。
echo $result; //这样写就会直接输出one这个字符串。
echo $result(2,3); //这样写则会输出5这个值,相当于实在调用函数了。
而当在某个函数的内部使用这种做法时,一般是这样的:
<?php
/*此处我懒,跳过声明函数的阶段,就直接使用之前定义的one函数*/
$result="one";
function two($result){
$a=1;
$b=2;
$result($a,$b);
return 1; //这样就实现了在函数之中对另一个函数的使用。
}
以上就是使用变量函数声明和应用回调函数的方式。
使用call_user_func_array()函数自定义回调函数:
这个函数是PHP中的一个内置函数,也是一个回调函数,格式如下:
mixed call_user_func_array(callback function/*这是要调用的函数名*/,array param_arr) //就像之前说的,有callback伪类型,就是回调函数
函数中有两个参数:第一个参数因为使用伪类型callback,所以需要是一个字符串,表示要调用的函数名;而第二个参数是一个数组类型的参数,表示的是参数的列表,按照顺序依次传递给要调用的函数。
使用方式及格式如下:
<?php
function fun($msg1,$msg2){
echo '$msg1='.$msg1;
echo '</br>';
echo '$msg2'.$msg2;
}
call_user_func_array('fun',array('XXX','AAA')); //使用该函数对fun函数进行调用,而array中的数据会按数据被传送到函数中,也就是说,fun函数中,$msg1会被赋值为'XXX',而$msg2会被赋值为'AAA'。
在数组中的元素个数必须和fun()函数的参数列表相同
类静态函数和对象的方法回调(需要结合面向对象来看):
之前的做法都是使用全局函数(没有在任何对象或类中定义的函数)声明和应用的回调函数,但如果是遇到回调类的静态方法,或是对象中的普通方法,则会有所不同。
递归函数:
简单来说,就是一个函数对自身的调用,就可以叫做是递归。一个自调用函数,在函数体内部直接或是间接的调用自己,就可以说是一个递归函数。
这个没什么好说的,常见函数利用方式而已。
使用自定义函数库:
关于函数库,这不是定义函数的PHP语法,只是一种设计模式。
如果想在同一个项目中的多个文件里面使用多个自定义函数,就可以用函数库的设计方式。
要调用函数库中的函数,就需要使用include()、include_once()、require()或是require_once()中的一个函数,将函数库文件载入到脚本程序之中。
在这其中:require()和include()函数的效果类似,都是包括并运行指定文件。不同之处在于对于include()语句来说,在执行文件的时候,每次都会有一个读取和评估的过程,而相对来说require()函数中,文件只会被处理一次(实际上,是文件内容替换了require()语句)
这就涉及到——如果只用读取一次文件,则使用require()更好,而要重复,多次的读取文件,就该考虑使用include()。
一般来说,require()函数放在函数的最前方,在执行前就会读入require()中引入的文件。而include()语句一般会放在流程控制的处理区段中,在读取到include()语句的时候,才会将它包含的文件读取进入。
一般来说使用:
<?php
require 'myfile.php';
include 'text.php';
include('other.php');
require('somefile.txt');
?>
因为这两种都是语言结构,所以,加不加圆括号都是可以的,与之相似的有echo函数。
注:关于其中的单引号和双引号问题,我在VSC里面尝试了一下,单双引号都可以使用,甚至前单后双都没有报错,具体差别,我会在以后了解了之后再添上来。
而相对这两个函数来说,那两个后缀里面带有once的,就是说在脚本的执行期间内,只会包含一个文件一次。
(嗯,我猜,这玩意儿会牵扯到文件包含漏洞)
PHP中的匿名函数和闭包:
在PHP5.3以前,使用的回调函数并不是很灵活,只有“字符串的函数名”和“使用”create_function的返回值两种形式。在PHP5.3之后,才新增了匿名函数这种特殊的形式,这种函数同时也叫闭包函数。
这个功能允许临时创建一个没有指定名称的函数,常用作回调函数的参数的值。
eg:
<?php
$fun=function($param){
echo $param;
}; //注意这个地方有一个分号。
/*将一个没有名字的函数赋值给一个变量$fun*/
$fun('www.ydma.com'); //在变量后加括号并传参数,调用匿名函数,输出网址
调用回调函数的时候,也可以将匿名函数作为参数的代码:
<?php
function callback($callback){
$callback();
} //参数只有是一个函数的时候才能在这里调用,这个地方是定义了一个叫做 callback的函数
callback(function(){
echo "闭包函数测试"; //调用函数的同时,直接传入一个匿名函数,就是说在调用callback函数的时候,传入的参数是function 那一堆。
});
//我自己试的时候,VSC爆了两个warning,但是还是可以运行
function(){
echo "闭包函数测试";
}
/*这个函数没有名称,是个匿名函数,同时没有设定参数,所以看起来才这么怪*/
闭包的一个重要概念就是可以在内部函数中使用外部变量
要达成这一效果,就要使用use关键字来连接闭包函数和外界变量,这些变量都必须要在函数或类的头部声明。闭包函数是从父作用域中继承变量,与使用全局变量是不同的。
全局变量存在于一个全局的范围,无论当前在执行的是哪个函数。而闭包的父作用域是该闭包的函数,不一定是调用它的函数。
use关键字使用:
<?php
function callback($callback){
$callback();
} //声明函数callback。
$var='字符串';
callback(function() use (&$var){
echo "闭包函数传参数测试($var)";
});
注意,在上面的例子里面调用var变量的时候,加了一个&符号,如果不加这个符号的话,所使用的就只是$var的一个副本而不是完全引用。(大概来说,应该是就算改变了副本的值也不会对于原来的变量值造成影响?)