5.2. 函数的使用
持之以恒,方得始终!
函数就是封装的一个能完成某一件事情的代码块。
我们可以类比接口,我们需要调用它,传递一些参数,它返回一定的结果。
当然了,调用函数,有的可能不需要给参数,或者没有返回值(默认则返回null)。
调用函数
一个最简单的调用
phpinfo(); // 不需要给参数,没有返回值,它打印出php的相关配置信息
一般我们调用系统内置的函数时,最好是查下手册,看下函数原型,参数说明,使用示例等。
我们已 fopen()
为例,看下它的函数原型
fopen(
string $filename, // 包含路径的文件名,字符串类型
string $mode, // 打开文件的模式,字符串类型
bool $use_include_path = false, // 是否使用设置好的路径,有默认值,表示其是可选的,布尔值类型
resource $context = ? // 远程打开文件使用,有默认值表示其是可选的,资源类型
): resource // 返回一个资源类型
注意:可选参数,一般都有默认值,不给就是使用的默认值。
注意:多个可选参数的情况下,我们不能这样做
fopen($filename, $mode, $context); // $context 其实是赋值给了$use_include_path参数了。
// 要想使用第四个参数,第三个参数我们必须得给。
fopen($filename, $mode, false, $context);
来实际使用 fopen 试下
$file = "./test/.htaccess";
$fp = fopen($file, 'rb');
var_dump($fp); // resource(6) of type (stream)
调用内置函数报错
可能偶尔会遇到这种情况
我们看到这种错误,可能有以下几种原因
- 函数拼写错误。
- php版本不对。
- 属于php扩展的函数,比如GD库,我们要想使用GD扩展库中的函数,则需要先开启这个扩展,载入它。
自己写一个函数
function add($n1, $n2) { // function固定语法,add函数名,()中的是参数
return intval($n1) + intval($n2); // 返回值
}
$res = add(3, 4);
var_dump($res); // int(7)
内置函数在所有脚本中都可以访问,但是自己声明的函数,只能在声明的脚本中使用。
我们可以创建一个 func.php 文件,用来存放我们自定义的函数,在需要的脚本中,require_once() 载入即可。
注意:php中,函数名称不能重复。
有些语言可能允许函数重名(和内置函数重名,和其它自定义的函数重名),这种叫函数的重载。
可变函数
$name(); // $name的值如果是 add,则这里等价于 add()
使用参数
function create_table($data, $border = 1, $cellpadding = 4, $cellspacing = 4) {
echo "<table border=$border cellpadding = $cellpadding cellspacing = $cellspacing>";
reset($data);
$value = current($data);
while($value) {
echo "<tr><td> $value </td></tr>";
$value = next($data);
}
echo "</table>";
}
$arr = ['Line one', 'Line two', 'Line three'];
create_table($arr, 3, 8, 8);
第一个参数是必须的,后面三个是可选的,都有默认值。
注意:可选参数一定是在必选参数的后面。并且不能跳着给。
func_num_args(), func_get_arg(), func_get_args()
借助于上面的三个函数,我们可以给任意个参数。func_num_args()
传入参数的个数。func_get_arg()
根据传参位置,获取一个参数。func_get_args()
获取所有参数,放入一个数组中。
function var_args() {
echo "参数的个数为:" . func_num_args() . PHP_EOL;
$args = func_get_args();
foreach($args as $arg) {
echo $arg . PHP_EOL;
}
}
var_args(1, 'a');
// 参数的个数为:2
// 1
// a
作用域
先看下 require(),include()
$varname = 'xxx';
require("./file.php"); // file.php中就可以直接使用到$varname变量了。
但是对于函数来说,函数外的变量是无法直接使用的,需要传参进去,或者使用 global , $GLOBALS
的方式。
我们再来回顾一下变量的作用域:
- 在函数内声明的变量,其作用域是从声明开始,到函数末尾,这叫函数作用域,这个变量称为局部变量。
- 在函数外声明的变量,其作用域是从声明处,到文件末尾,而不是函数内部,这叫全局作用域,这个变量称为全局变量。
- 超级全局变量在函数内外都是可见的。
- 使用require(), include并不影响作用域,如果它们用于函数内部,函数作用域适用,如果是外部,全局作用域适用。
- 关键字 global,可以在函数中,声明一个全局变量。
我们来看一些例子:
function add() {
$var = "contents";
}
add();
echo $var; // 会正常输出contents吗,因为作用域不同,会报变量不存在的错误。
上面的执行顺序是:
- 先在全局作用域下创建了一个 $var 变量。
- 然后调用了 add() 函数,里面先打印 $var,但是此时是函数作用域,和外部没关系,会报变量未定义的错误。然后又在里面创建了一个 $var变量,再次打印,则有值输出。此时函数执行完毕,里面的变量自动被销毁。
- 最后 echo $var, 这是全局作用域下,访问的就是调用函数之前的那个 $var。
function add() {
global $var;
$var = 'contents';
var_dump($var);
}
add();
var_dump($var);
//string(8) "contents"
//string(8) "contents"
上面的例子中,函数内的 $var 被声明为了全局变量,同时它又在函数内部,所以函数内外都可见。
参数的值传递,引用传递
值传递,是创建一个原来变量的副本给函数,不影响原来的变量。
function increment($value, $amount = 1) {
$value += $amount;
}
$value = 10;
increment($value);
echo $value; // 依旧是10,函数中的改变不会影响外部的,除非使其为全局变量,或者还可以使用引用传递。
引用传递,是获取原来变量的引用,函数里面的改变,会影响外部的。
function increment(&$value, $amount = 1) {
$value += $amount;
}
$a = 10;
increment($a);
echo $a; // 11
return关键字
它在函数内,有两个作用:
- 终止函数的继续执行,然后返回到函数调用处,继续处理后续代码。
function getMaxNum($n1, $n2) {
if (empty($n1) || empty($n2)) {
return 'param error'; // 不满足条件,终止函数的执行,并返回一个结果到函数的调用处
}
// 条件满足,处理业务
return $n1 > $n2 ? $n1 : $n2;
}
$maxnum = getMaxNum(1);
var_dump($maxnum); // 参数少了,这里会报错
- 返回一个值到调用处。
递归
简单说,就是函数调用自身。其实和循环一样,都是重复的做一件事情。它比较适合处理树状结构的数据。
我们来写个递归的例子,把字符串颠倒。
function reverse_r($str) {
// 如果字符串非空,截取前面的一位,再次传给自身,比如 hello, reverse_r('ello')
if (strlen($str) > 0) {
reverse_r(substr($str, 1));
}
echo substr($str, 0, 1); // 取第一位字符
return;
}
reverse_r("hello"); // olleh
我们来分析下执行过程:
因此整个输出结果就是 olleh
注意:不要忘记给递归一个终止条件,否则会一直递归下去,直到内存耗尽。
递归会在内存中创建很多自身的副本,将产生多次函数调用的开销。
我们再用循环实现一下:
function reverse_i($str) {
for ($i = 1; $i <= strlen($str); $i++) {
echo substr($str, -$i, 1);
}
return;
}
reverse_i('hello'); // olleh
所以,除非循环不好实现,或者代码写起来非常复杂,才用递归。
如有任何侵权行为,请通知我删除,谢谢大家!
个人邮箱:865460609@qq.com