admin管理员组文章数量:1588121
本文章是我在b站上自学PHP的学习笔记,如果有错误,欢迎大家改正,谢谢。
文章目录
- 1. PHP介绍
- 1.1 什么是PHP
- 2. 认识PHP脚本程序
- 2.1 PHP语言标记(四种定界符)
- 2.2 结束定界符是否可以省略?
- 2.3 PHP程序的最后一段代码是否可以省略分号?
- 2.4 注释
- 2.5 空白符处理
- 3. PHP页面乱码问题
- 3.1 meta标签型
- 3.1 header()型
- 4. PHP的输出语句
- 4.1 echo
- 4.2 print
- 4.3 print_r
- 4.4 var_dump()
- 4.5 printf
- 5. 变量
- 5.1 变量的概述
- 5.2 变量的命名规则
- 5.3 变量是否区分大小写
- 5.4 变量的创建
- 5.5 变量的传值和传地址
- 5.6 变量的销毁
- 5.7 可变变量
- 6. 如果没有Apache,php能否执行php页面?
- 7. 二进制
- 7.1 二进制的简单概述
- 7.2 转为十进制
- 7.3 转为二进制
- 8. 数据类型
- 8.1 数据类型的简单概述
- 8.2 数据类型的分类
- 8.3 PHP的八种原始的数据类型
- 8.3.1 四种标量类型
- 8.3.2 两种复合类型
- 8.3.3 两种特殊类型
- 8.4 伪类型
- 9. 数据类型的相互转换
- 9.1 自动类型转换
- 9.2 强制类型转换
- 9.3 跟bool的转换规律
- 10. 常量
- 10.1 常量的简单概述
- 10.2 常量的命名规则
- 10.3 常量是否区分大小写
- 10.4 声明常量的几种方式
- 10.5 常量名如果含有特殊字符
- 10.6 重复定义常量
- 10.7 预定义常量(系统常量)
- 10.7.1 预定义常量有哪些
- 10.7.2 魔术常量(不区分大小写)
- 11. 运算符
- 11.1 运算符的简单概述
- 11.2 算术运算符
- 11.3 字符串运算符
- 11.4 赋值运算符
- 11.5 比较运算符
- 11.6 逻辑运算符
- 11.7 位运算符
- 11.8 其它运算符
- 12. 运算符的优先级
- 13. 流程控制
- 13.1 流程控制的简单概述
- 13.2 单分支
- 13.3 双分支
- 13.4 多分支
- 13.5 多路判断switch
- 13.6 替代语法
- 14. 循环执行
- 14.1 for
- 14.2 while
- 14.3 do-while
- 14.4 foreach
- 15. break和continue
- 16. PHP的执行过程
- 16.1 认识内存
- 16.2 php的执行过程
- 16.3 php嵌入到HTML的执行过程
- 17. 函数
- 17.1 何为函数
- 17.2 自定义函数
- 17.2.1 函数的定义
- 17.2.2 函数的调用
- 17.2.3 函数的参数
- 17.2.4 函数的返回值
- 17.2.5 匿名函数
- 17.2.6 可变函数(变量函数)
- 18. 变量的范围
- 18.1 局部变量
- 18.2 全局变量
- 18.3 静态变量
- 19. 参数传递(按值传递和按引用传递)
- 19.1 按值传递
- 19.2 按引用传递
- 20. 递归函数(可以理解函数调用的过程)
- 21. 内置(内部)函数
- 21.1 获取变量的类型
- 21.2 字符串处理函数
- 21.3 与html标出相关的函数
- 21.4 处理数组的相关函数
- 21.5 判断是否为某种类型
- 21.6 判断变量是否为空
- 21.7 与二进制相关的函数
- 21.8 数学函数
- 21.9 可变长度参数列表
- 21.10 创建函数
- 21.11 判断函数是否存在
- 21.12 其它
- 22. 参数类型约束declare
- 23. 函数返回值约束(php高版本才有,比如PHP7)
- 24. 终止脚本执行
- 24.1 exit() / die()
- 24.2 return
- 25. 错误处理
- 25.1 错误分类
- 25.2 错误代号
- 25.3 错误触发
- 25.4 错误设置
- 25.5 自定义错误处理
- 26. 正则表达式
- 26.1 何为正则
- 26.2 语法规则
- 26.3 与正则表达式匹配的函数(1)
- 26.4 与元字符搭配
- 26.5 贪婪匹配
- 26.6 模式修正符
- 26.7 与正则表达式匹配的函数(2)
- 27. 日期与时间
- 27.1 设置时区(解决时间差)
- 27.2 当前Unix时间戳
- 27.3 指定时间的Unix时间戳
- 27.4 从Unix时间戳取得时间日期信息
- 27.5 获取Unix时间戳和微秒数
- 27.6 检查日期是否合法
- 28. 文件与目录操作
- 28.1 判断普通文件和目录(文件夹)
- 28.2 文件的属性
- 28.3 目录的基本操作
- 28.4 文件的基本操作
- 29. 文件上传
- 30. 文件下载
- 31. 包含文件
- 31.1 路径问题
- 31.2 require() 和 include()
- 31.3 require() 和 include()两者区别
- 31.4 include_once() 和 require_once()
- 31.5 注意点
- 31.6 ./目录/文件 和 目录/文件 的区别
- 32. namespace隔离函数
- 33. 会话管理
- 34. 排序
- 34.1 排序的简单概述
- 34.2 冒泡排序
- 34.3 选择排序
- 34.4 插入排序
- 34.5 快速排序
- 35. 查找
- 35.1 二分查找
- 36. json处理
1. PHP介绍
1.1 什么是PHP
PHP是一门服务端的编程语言。它是用C写的,它的英文名叫PHP: Hypertext Preprocessor
,中文名叫“PHP超文本预处理器”。
- 超文本:HTML就是一种超文本。
- 预:预先。
- 处理器:生成,处理。
合起来就是“预先生成,处理出一个HTML代码”。更准确的说是“PHP是一门服务端的编程语言,可以用来生成HTML代码”。
PHP主要适用于web开发领域。所以具有开发速度快的特点,用于中小型企业比较多。
总结:
- PHP是一个编程语言。
- PHP是处理PHP编程语言的一种软件(超文本预处理器)。说白了,PHP语言必须运行在PHP软件上。PHP软件就相当于PHP的运行环境,运行环境可以理解为是一个翻译官。专门来翻译PHP语言的,类似于Java的jvm。
问答:
1. 什么是PHP?
答:PHP是超文本预处理器,是一门服务器端编程语言,用于执行PHP程序生成HTML代码。
2. 可以用什么方式证明PHP在服务器端执行php代码生成html的?
答:如图:
2. 认识PHP脚本程序
此处省略了PHP的安装环境,大家自行上网安装。
安装好编辑器后,打开编辑器,可以是Zend Studio,PhpStorm,或者记事本,甚至是HBuilder,都行。要注意文件扩展名是.php。还有注意文件要放到你的站点根目录下,这样,php才能运行,放到站点外是不能执行php代码的。
2.1 PHP语言标记(四种定界符)
定界符可以理解为就是PHP的管辖范围。
-
标准风格(推荐使用)
<?php // PHP代码 ?>
-
短标记风格
<? // PHP代码 ?>
注意:用短标记风格是不起作用的,也就是默认不支持短标记风格,必须在php.ini中更改配置如下,编辑php.ini,定位到short_open_tag = off,把off改为on即可。
-
asp风格
<% // PHP代码 %>
注意:默认情况下也不支持asp风格,需要在php.ini中更改,找到asp_tags,把off改为on。
-
脚本风格
<script language='php'> // PHP代码 </script>
是不是跟js很像,我们以前写js的时候,是不是写在<script>标签里面,和</script>标签结尾,就表明我里面写的是js代码,同理,php也是这样,在一个html页面中,会有一个逻辑,我需要加上一个标记,告诉计算机我里面的代码是php代码,归php解析器去解析。
解读:
- "<?php" 表示开始," ?>"表示结束,中间写PHP代码。在开始和结束标记之外的内容都不会被PHP解析器解析,一般之外的都是写html代码。其他三种都一样。
- PHP是一个脚本语言,它可以直接嵌入到html代码中,并且可以嵌入到html代码中的任何地方,在一个html文档中可以嵌入任意多个PHP标记,要注意是以.php结尾的PHP文件。别在html文件里写php。
2.2 结束定界符是否可以省略?
在html中,我们要加粗某个文字,比如<strong>床前</strong>明月光,我们发现只有 “床前” 这两个字加粗了,如果我们把</strong>去掉,没有结束标签,那么从开始标签开始,一直往后,都是加粗的内容,直到</html>才为止,以此类推,php也是这个道理。从 “<?php” 表示开始,到 “?>” 表示结束,如果把结束符 “?>” 去掉,那么从 “<?php” 开始往后都是php代码。所以,php的结束符 “?>” 可以去掉吗?
答案是看情况而定,如果你的“<?php” 往后都没有除了php代码的其他标签,比如html标签,哪结束符就可以省略,如果有html标签,哪就不能省略。
所以总结:php支持省略结束定界符。
2.3 PHP程序的最后一段代码是否可以省略分号?
好,现在我们知道它是可以省略结束定界符的,但还有一个细节,就是最后一个输出语句加不加分号的问题,首先,我们明确一点,php的一个语句的结束,必须是要加分号的,表示结束,但是到了php代码的最后一条结束语句,要不要加分号,得看结束符 “?>” 的脸色,比如现在下面有两段代码,大家可以复制到自己的编辑器比较一下:
<?php
echo 'helloworld<br>'; //要加分号表示结束,不然报错
echo 'hahaha' // 为PHP的输出语句,后面会介绍
//此处有结束符
?>
<?php
echo 'helloworld<br>'; //要加分号表示结束,不然报错
echo 'hahaha'
//此处没有结束符
以上两段代码,输出语句hahaha后面是没有分号的,区别在于一个有 ?> ,一个没有?>,当我们把它粘贴在编辑器,会发生什么呢?很明显,第一段代码没有报错,正常输出。第二段代码就不行了,报错了,这是不是可以得出一个结论:?>相当于一个分号,不然你们在第二段代码的最后一个输出语句加个分号试一下,是不是跟第一段代码的效果一致,这不就说明?>相当于一个分号吗?
最后说明一点,隐含两个分号是没有关系的,比如你即加上分号,又加上?>,是没有关系的。
2.4 注释
- /* 多行注释 */
- // 单号注释,#也是单号注释
注意:php注释你右击查看网页源代码是看不到的,而html注释可以看到,这也是php跟html的不同之处。
2.5 空白符处理
空白符包括空格,tab制表符,换行,这些在PHP中都是无关紧要的(注意都是英文输入法下输入的),可以将一个语句展开成任意行,或者紧缩在一行,空格与空行的合理运用可以增强代码的清晰性与可读性,如果运用不合理反而会对阅读产生负担!
3. PHP页面乱码问题
如果我们的输出语句里有中文,哪就会出现乱码(前提是你的编辑器环境是UTF-8的,因为有些编辑器的默认编码是gbk,在这种环境下测试乱码,将不会出现乱码),出现乱码该怎么解决呢?当我们把他放到html页面中的body体内,就不会乱码了,因为html当中有这么一个标签<meta charset=UTF-8">起的作用,告诉浏览器用utf-8来解决,所以,解决方法一如下:
3.1 meta标签型
<meta charset="UTF-8">
<?php
echo '我喜欢你!!!';
或者
<?php
echo '<meta charset="UTF-8">';//在PHP介绍哪章就说了php是可以生成html的,所以我们可以输出html标签
echo '我喜欢你!!!';
3.1 header()型
<?php
header('content-type:text/html;charset=utf-8');//通过header函数设置响应头信息告知浏览器发送的是html内容utf-8编码
echo '我喜欢你!!!';
content-type告诉浏览器我要以html形式展示,你也可以让它用图片的形式展示,就好像我给你了一个东西,同时还告诉你这东西要怎么做好吃,怎么用。
4. PHP的输出语句
输出语句?废话,输出语句就是让你想表达的东东输出到浏览器页面上,让被人打开页面就可以看到你的哪个东东,你可以理解,你在网上看到的一切数据都是输出语句输出来的,输出语句有哪些呀?没错,有以下的四大金刚:
4.1 echo
<?php
header('content-type:text/html;charset=utf-8');
echo '我喜欢你!!!<br>';
echo 10,'<br>';
echo true,'<br>';
echo false,'<br>'; //echo null也是空空如也
echo array(10);
效果如下:
图上报的错是数组的错,所以,echo可以输出字符串,数字,输出布尔型虽然不报错,但是不合适,因为你不知道1是布尔型true,还是数字1,数组不能输出里面的元素,只能显示Array,echo可以依次输出多个值,每个值用逗号隔开。
有人要问:“啥叫可以依次输出多个值呀”?如下:
<?php
echo "haha";
echo "baba";
/* 上面是不是两句话,我能不能一句话输出?懂了吧 */ echo "<hr>";
echo "haha","baba";
细节:echo的另一种表示方法,带括号,比如:echo(“i love you”),照样可以输出,但是echo(“i love you”,“me?”)这样却不行,这也是它与echo不带括号的区别,所以带括号,只能放一个参数。
4.2 print
<?php
header('content-type:text/html;charset=utf-8');
print '我喜欢你!!!<br>';
print '10<br>'; //不要写成 10.'<br>';
print true.'<br>';
print false.'<br>';
print array(10);
细节:与echo的区别注意放在输出语句上,echo是逗号,而print是点(实质是字符串的连接)。否则将报错、代码效果如下:
发现结果跟echo一样,但它跟echo的区别是print它只能输出一个值。
<?php
header('content-type:text/html;charset=utf-8');
$n=print 'haha'.'mama';
echo '<br>',$n; //结果是1
这说明了print输出成功返回1,输出失败返回0。代码中是print的结果赋值到$n,然后echo输出,是赋值操作,后面会讲。
注意:这里我要说一下字符串连接符点,为什么要说它,我上上面不是贴了一个代码,代码里有个注释写着:“不要写成 10."<br>",为什么不能这么写,其实我也不清楚,如果说字符串连接符点的左右两边必须是字符串,那不能写成10."<br>",可以理解,为什么true."<br>“就可以呢?是不是true被隐式转换为字符串1,如果这样,那为什么(int)true.”<br>“也是可以呢?不就变成1.<br>了吗?这个想不通,就从另一个方面想把,如果你试了去输出"true<br>”,你就会发现true是原样输出的,放在引号外面,用点相连,它就会隐式转为为1。但是你2."<br>“就不一样,它可能会以为是浮点数,所以报错,也就是说,没必要这么写,直接"2<br>”,就行了。或者说直接这样:(2)."<br>"。给2加上括号,也是可以的。这样他不会认为是浮点数,当然,这只是我的理解,如果你觉得理解的比我好,欢迎提出来。
4.3 print_r
<?php
header('content-type:text/html;charset=utf-8');
print_r('我喜欢你!!!<br>');
print_r('10<br>');
print_r(true.'<br>');
print_r(false.'<br>');
print_r(array(10));
效果如下:
我喜欢你!!!
10
1
Array ([0] => 10 )
前四个的结果跟上面一样,但数组它显示出来了,说明print_r是可以输出数组的
4.4 var_dump()
<?php
header('content-type:text/html;charset=utf-8');
var_dump('我喜欢你!!!');
var_dump('10');
var_dump(true);
var_dump(false);
var_dump(array(10));
效果如下:
string '我喜欢你!!!' (length=21)
string '10' (length=2)
boolean true
boolean false
array (size=1)
0 => int 10
我们发现,在输出字符串和数组的时候,它除了输出值,还输出了类型和长度,数组跟pring_r一样也可以输出属性值,还有一点,输出布尔型最好用var_dump()。想简单的输出数组用print_r即可。
4.5 printf
printf意为格式化输出字符串。
<?php
$number = 20;
$str = "广州";
printf("我在%s,今年%u岁了",$str,$number); //我在广州,今年20岁了
//第一个%s,和第二个%u。和后面的参数$str,$number一一对应,即
//%s 和 $str 对应
//%u 和 $number 对应
//注意,是字符串第一个出现的%和printf的第二个参数对应,以此类推,反正就是一一对应
//也就是说以%开始的是一个占位符,像上面就有两个占位符,但是%后面的字母是有特殊含义的,
//比如%s中的s,和%u中的u,都是有特殊含义的,s代表字符串,u代表正整数,如下表
/*%% - 返回一个百分号 %
%b - 二进制数
%c - ASCII 值对应的字符
%d - 包含正负号的十进制数(负数、0、正数)
%e - 使用小写的科学计数法(例如 1.2e+2)
%E - 使用大写的科学计数法(例如 1.2E+2)
%u - 不包含正负号的十进制数(大于等于 0)
%f - 浮点数(本地设置)
%F - 浮点数(非本地设置)
%g - 较短的 %e 和 %f
%G - 较短的 %E 和 %f
%o - 八进制数
%s - 字符串
%x - 十六进制数(小写字母)
%X - 十六进制数(大写字母)*/
?>
5. 变量
5.1 变量的概述
程序在哪里执行?
计算机方便了我们的生活,比如我以一个简单的加减运算为例,有了计算机,我们就不用自己拿着笔在草稿纸上运算。我们可以把它交给计算机,让计算机帮我们运算,那么计算机跟我们一样,它也需要一张草稿纸,这个草稿纸就是内存,内存是干嘛的,简单的说是存放临时数据的,计算机会把我们给它的算术拿到内存当中进行计算,计算的结果就放在内存当中。
为什么要有变量?
我在上面不是说了php的输出语句吗,好,如果我写了一段代码给计算机去执行,如下:
<?php
echo "你跟妈妈说我要吃肉";
echo "小米说我要吃肉";
echo "小刚跟小花说我要吃肉";
echo "小美故意跟他妈说我要吃肉";
echo "小张饿的不行说我要吃肉";
我们发现,在每一个输出语句上都会有重复的一段话,叫"我要吃肉",4个字,不多,但是如果字数很长,是不是显得很累赘,那么我们可不可以在内存中开辟一块空间,把那个重复的东西放到哪块空间里,并给这空间起一个名。我要用,我拿它的名字就可以了,我也不用写那4个字,可不可以,答案是可以的。解决办法请看后面的"变量的创建",反正从这一点可以看出变量是不是可以解决复用性的问题。
变量的理解
在前面说过把那个重复的东西放到一个独立的空间,并给空间起一个名。这个名就是变量名,那块独立的空间就是内存当中的一块小空间,里面存着那个重复的数据。数据可以是数字比如123456…。它里面的值可以变,比如说,我不想吃肉了,我想吃鱼,可不可以,当然可以,它会变,所以叫变量,不管你怎么变,你里面的存放的值还是数据。实质上变量就是存放数据的一块临时空间(只有在我们的程序运行过程中才存在),为什么说它临时,因为它在内存中。
在编程语言中,变量是最简单的一种存储类型,一个空间里面只放一个值,一对一的关系。也有一对多的关系,这是后话。我们只说变量,另外,PHP脚本语言是一种弱类型语言,和其它语言不同的是变量或者常量的数据类型由程序的上下文决定。啥叫数据类型呀?我们人是不是分女人和男人,是不是两种类型,也就是说一个厕所它男的可以上,女的也可以上,PHP就是这样的一个厕所,因为它弱嘛!!!所以我可以根据进来的人是男的还是女的判断这个厕所是男厕所还是女厕所。总结:数据类型是一种对变量的分类,但是PHP对这分类似乎不太关心。
5.2 变量的命名规则
变量名必须以美元符号$开头,比如$name,也就是$变量名, $不是变量的一部分,仅仅表示变量名的开始,从$往后都是变量名。除了$以外,变量名必须以字母,下划线开头,数字不能开头,后面跟的是字母,下划线,数字。
总结:很简单,变量名它只能是字母,数字,下划线组成,其他的统统不可以,比如什么%啊,*号啊这些特殊符号都不可以,还有注意变量开头的不能是数字就ok了。
5.3 变量是否区分大小写
变量是严格区分大小写的。
5.4 变量的创建
变量的创建,我先说一下有个东西叫声明,说白了就是事先通知,举个例子,就是说,有个罐子,我事先就以一种明白的口气跟你说,这个罐子只能放糖,其它啥都不能放。注意哦!是只能,你放了,我就报错,就这意思,但是这是强数据类型的特点,我们PHP是弱数据类型,对数据类型并没有那么上心,比如上面有个厕所的例子。所以,我们PHP是不需要声明的,再说通俗点,是一个变量的创建不需要声明,你放什么就是什么。
既然我们知道什么是数据,变量名是怎么命名的,接下来,就是把数据往里一放,放进去,意味着变量的创建。
那么咋放捏,诶,有个东西叫赋值运算符,"=",在数学里,它是相等的意思,但在这里,它是赋值,放的意思,代码如下:
<?ph。
//格式:$变量名=数据;
$abc = 1; //表示将1赋值给变量$abc;
注意,变量一旦创建,意味着它在内存里有一段空间给它存着,这块空间是有名字的,叫$abc,里面存着数字1。同时,变量必需要给它赋一个值。
好,现在我们来解决上面“我要吃肉”的问题,代码如下:
<?php
$eat = "我要吃肉";
echo "你跟妈妈说$eat";
echo "小米说$eat";
echo "小刚跟小花说$eat";
echo "小美故意跟他妈说$eat";
echo "小张饿的不行说$eat";
$eat = "我要吃鱼";
echo "小米说$eat";
5.5 变量的传值和传地址
我们知道变量是存在内存当中的一块空间,那么存在内存当中,那么它就应该有那块空间的地址,比如显示中的哪个省哪个市哪个区哪个小区门牌号多少。但是因为地址太长了,不好记,所以我们给它其了一个名字,也就是变量名,它里面住的人就是数据。
我想说明什么问题呢?我们刚刚学过了变量的赋值,就是怎么放进去,那么在计算机的世界了,它放进去的不一定是具体的值,它可能是地址,如下代码:
传值:
<?php
$a=10;
$b=$a;
$a++;
echo $b;
解读:有一块空间叫$a,然后我把$a里面的值复制一份给名字叫$b的这块空间,实质上是两个空间,谁也不影响谁,你$a的值变了,并不会影响我$b的值。
传地址:
<?php
$a=10;
$b=&$a;
$a++;
echo $b;
解读:$变量名在赋值的时候赋的是值,如果在$前面加上&符,哪就是&$变量名,这表示赋的是变量的地址。你$a把你所在的空间地址给了$b,那么你跟$b不就共享一个空间吗?
总结:
传值,保存值的空间是两个,更改一个空间的值,不影响另外的变量;传地址,保存值的空间就一个,更改一个变量的值,另一个变量也会变化,因为两个变量指向同一个空间。
5.6 变量的销毁
先看下面这幅图:
上幅图右边有一大串的文字,大家可以细细品味一下。下面的例子都跟上副图有关系。
unset()
我上图就说了,PHP有一个函数叫unset()是来吧一个变量名从变量表里擦除掉的,从而达到销毁变量的效果,那么咋毁,很简单,你要把谁毁了,你就把哪个人的名字往括号里一写就完事了。
但是它并不是指将该变量从程序中删掉,而是,“断开"该变量名跟该变量原有的数据值之间的"引用关系”(联系),只要大家能够读懂我上副图的那一大串话,你就能明白,变量名擦除掉了,那根线还有意义吗,是不是断开联系了,擦除掉,就是把变量名从变量表里移除,移除掉,就是NULL,那怎么证明它是NULL呢?有一个函数isset(),它的意思就是"判断变量是否有值,并且值不为null"。也就是说,为null就是false咯。
还是那句话,“此null非彼那个null”。接着看下面的代码:
上面两个报的错是一样的,没有一个人的名字叫$haha,我能理解,$abc报的错跟$haha报的错一样,就好像这世上没有一个人的名字叫$abc,也就是说,这个名字它不存在了,这个人死了,连它的名字也消失了,我想说明什么?如下代码:
<?php
$a=10;
$b=&$a;
unset($a);
echo $b;
以上代码的作用是证明unset销毁的是变量名,还是变量值,如果销毁的是变量名,哪$b输出10,如果销毁的是变量值,那么$b不会输出10,因为$b和$a指向的是同一个空间,事实证明,$b会输出10,说明unset销毁的是$a的变量名,就是把你这个人的名字给抹去,就好像这世上没有一个人叫$a。它不会对你的那块空间产生影响。
注意:变量值是由php的垃圾回收机制回收,垃圾数据就是没有变量引用的数据。
5.7 可变变量
<?php
$a='床前明月光';
$b='a';
echo $$b;
?>
上面的,$$b
就是$a,因为$b等于a,所以这不难理解,$$b就是“床前明月光”。
可变变量就是将变量名存储到另一个变量中,$b保存的是变量a,注意变量中还可以存储函数名。
6. 如果没有Apache,php能否执行php页面?
没有apache,就是没有http来执行。是可以的,打开cmd,输入命令:php.exe 文件的路径 ,回车,即可得到执行,这就是通过命令行来实现,但问题有来了,传参要怎么传?$_GET和$_POST用来获取http提交的参数,不能获取命令行提交的参数,通过命令行传递参数通过$argv获取参数的值,$argc用来传递参数的个数,如:
<?php
echo $argv[0]."\n";
echo $argv[0]."\n";
echo $argv[0]."\n";
echo "arguments count:".$argc;
然后执行命令,第一个参数就是它的路径,第二个和第三个呢?在命令行中:php.exe 文件路径(参数一) 参数二 参数三,各个参数用空格隔开。大家自行测试。
7. 二进制
7.1 二进制的简单概述
在计算机中,他们所处理的很多数据甚至庞大的数据都会被转换成0和1,也就是说,用0和1就可以表示世界上的万物,它是计算机最底层的语言,区分与我么现在学的高级语言php,我们并不会直接操作0和1,但是它却是计算机懂的语言,我么学的高级语言php,写的代码最终都会被转换成0和1,也就是二进制,计算机为什么采用二进制,其实对于计算机而言,二进制才是最简单,最方便实现的进制,它比十进制更加稳定,当然还有更深的原因。
除了二进制,还有八进制,十进制,十六进制。
7.2 转为十进制
7.3 转为二进制
那如果小数要转为二进制呢?
为了更深入的了解小数转为二进制,我们把27.87转为二进制,这个懂了,那就真的懂了!!!
- 小数分为整数部分,和小数部分,小数点前面的是整数部分,很明显,整数部分是27,那么就按照"除2反向取整"的法则去进行。小数点后面的是小数部分,那么就按照"乘二正向取整" 的法则。
- 要注意小数部分的乘法运算,如0.74*2=1.48, 那么取整,就是1,1被取走,就是0,所以,结果是0.48,再用0.48去乘以2即可,说来说去,就是要保证在小数部分的乘法运算中整数部分一定是0。
- 小数部分可以不断往下乘,直到小数部分等于零为止。小数部分结果如果太长,可以取近似值,因为小数部分有时候不能乘尽,比如0.2,后面有例子。
- 然后把算出来的整数部分(也就是27)和小数部分(也就是0.87)进行拼接,比如27算出来是11011,0.87算出来是1101,那么拼接就是11011.1101。如图:
为什么小数不能用来比较,这牵扯到后面的浮点数。如图:
PHP变量中可以存十进制,八进制,十六进制。
<?php
$num1=10; //十进制
$num2=010; //八进制(8进制声明: 以0开始,后面跟0-7的整数)
$num3=0x10; //十六进制(16进制声明: 以0x开始,后面跟0-f的,0x的abcdef不区分大小写。)
var_dump($num1,$num2,$num3); //int(10) int(8) int(16) 你用echo也是打印出一样的效果10 8 16
8. 数据类型
8.1 数据类型的简单概述
变量类型是指保存在该变量中的数据类型,在计算机编程语言世界中每个数据都有它的类型。具有相同类型的数据才能被彼此相互操作。
8.2 数据类型的分类
变量的数据类型分为强数据类型和弱数据类型,如果一个变量的类型取决于存放值的类型,这种语言称为弱类型语言,如果声明变量是A类型,就不能存放B类型的数据,这种语言就是强数据类型 语言。PHP和js都是弱类型的语言,java和C语言都是强制类型的语言(当中php的底层就是C语言)。
好比一个罐子,你妈说这个罐子只能放鱼,不能放其它,放其它就要打死你,这就是强制性的,你妈事先跟你声明好了。如果你妈说随便放,哪就取决于你放的东西叫什么,是鱼就是鱼罐,是李子就是李子罐,是蜂蜜就是蜂蜜罐。。。这就不是你妈对你的强制。
8.3 PHP的八种原始的数据类型
四种标量类型:boolean,integer,float,string。两种复合类型:array,object,最后是两种特殊类型:resource,NULL(当变量的值为null时,该变量的数据类型就是NULL)。
8.3.1 四种标量类型
- 布尔
布尔值只有两个true和false。就是真和假。如果一个变量里面存的是布尔值true或false,哪这个变量就是布尔型 - int
int就是整形,比如1,2,3…包括负整数,-1,-2,-3等等。整数通常情况下是四个字节。1个字节等于8位。比如数字1,用二进制表示就是:00000000 00000000 00000000 00000001。说明一下,最高位的0表示正数,后面在讲位运算符会涉及到。 - float(也称double)
浮点数,就是小数,而浮点浮点,就是这个小数是浮的,它跟整形不同,它保存在计算机当中是个近似值,为什么?前面我们在,小数转为二进制的例子,是乘2正向取整,有的时候,小数转为二进制,可能会一直循环下去,这就是导致为什么浮点数不精确,正因为不精确,所以才不能拿来做比较。浮点数也叫单精度,但是在java,C,C#中,浮点数有两种,一种是单精度(float),还有一种是双精度(double),双精度的范围比单精度要广,在PHP中,float和double是一样的,没有区别,所以php没有单精度和双精度之说。注意不要拿浮点数来做比较,比如var_dump(0.1==(1-0.9));它的结果是false,并不是true,按照我们的想法,1-0.9就是0.1,当恰恰相反,它是false的,但如果我就想比呢?那怎么比,这就有用到一个函数了,bccomp()。它里面有三个参数,bccomp(值1,值2,比较的位数)去比较浮点数,如果两个数相等返回0,值1>值2返回1,否则返回-1。如:echo bccomp(0.1,(1-0.9),5);表示0.1跟(1-0.9)相比,如果前5位一样,那就相等,结果是相等的,echo bccomp(1.123,1.124,2); 比较前二位(12和12),相等,但如果比较前3位(123和124),不相等,返回-1,值1的123小于值2的124。最后浮点数的范围比整形大,如图:
- string(字符串)
字符串是一系列的字符。
字符串可以使用单引号,双引号,字符串定界符三种方法来定义。
在JavaScript中 单引号 和双引号没有区别,只要成对使用就行,但PHP就不同了。-
单引号
<?php $a='test'; var_dump($a);
t是一个字符,e是一个字符,t e s t这4个字符就组成了字符串,它是由单引号引起来的字符串,当然字符当中包括你敲的空格。
注意:在单引号括起来的字符串中不能再包含单引号,如果实在要用单引号那么就需要反斜杠(\)转义。
单引号字符串中出现的变量不会被变量的值替代,即PHP不会解析单引号中的变量,因此在定义简单字符串的时候,使用单引号效率会更高,因此没有特别的要求,应使用单引号定义字符串! -
双引号
双引号也是输出字符串的,那么它跟单引号的不同是在解析变量反面的不同。如图:
如果字符串内没有变量,显示结果单引号和双引号是一样的,但是执行效率单引号优先,图上代码说明双引号可以解析变量,正因为要解析变量,所以双引号的效率要比单引号低。易错点
从中可以看出,输出语句中有一条红线提示报错,为什么呢?那是因为它找不到一个变量叫做"$test你好呀!",按道理说,变量不是"$test"吗?但其实不是,这其实我们在上面讲定界符的时候就说了,道理都是一样的。它会以$开始,表示变量的开始,然后一直往后延伸,所以这时候我们需要一些特殊字符来区分。
-
空格
<?php $test = '朋友'; echo "小$test 你好呀!"; //输出 小朋友 你好呀!
-
括号
除了以上的空格,括号外,还有逗号之类的,反正就是不要让它跟后面的非特殊字符紧挨在一起,我们可以在它们之间加上一些特殊字符间隔开,这样变量就会得到解析了,但是效果却不是我们想要的,我们想要的效果是"小朋友你好呀!“这一整句话,而不是中间有空格,逗号什么的,那该怎么做呢?其实只需要在你的变量周边括上花括号”{} "
-
花括号{}
<?php $test = '朋友'; echo "小{$test}你好呀!"; //输出 小朋友你好呀!
当然,${test}这样也是对的,只要$和{ 挨在一块就行了。
ASCII码
- Ascii码原文叫:美国标准信息交换码。
- 主要目的是用于在计算机里面表示字符。每个英文字母都有一个数字表示,如图,是一个简化版的ASCII码表。里面还有标点符号等:
- 为什么要用ASCII表,是因为计算机内部全是数字,但人交流时用的是字母符号。
- ASCII用来表示英文单词,然后Unicode表用来表示全世界所有的文字。
计算机的内部使用的是二进制,键盘输入a,计算机怎么知道是a的呢?其实,每一个键盘都有一个对应的数字与之匹配,这个数就是ASCII码,然后再通过ASCII码转为二进制。试题:已知A=65,求d: d-D=32,d-(A+3)=32,d=32+A+3,d=100。注意,小写字母比大写字母大,小写字母和大写字母相差32,ASCII是连续的。php有一个函数是让字母转为ASCII码的,
echo ord('a')
; 与之相反,echo chr(65)
,ord将字符转成十进制的ASCII码,chr是将十进制的数字转成字符。转义字符可以转义ASCII码,如:echo “\101”;结果是A,它是将八进制的ASCII码转为字符。echo “\x41”; 它是将16进制的ASCII码转成字符。
上面的echo "\101";结果是A
说明了什么?
是不是说明了在字符串里面如果转义字符里面有数字,它会把它当成八进制的ASCII码来转成字符,有个前提,它必须是双引号,而不是单引号。单引号和双引号的区别
除了以上解析变量,转义ASCII码,执行效率的区别之外,还有一个区别,便是转义字符的区别。
其实上面说明了但引号定义的字符串中可以转义单引号和转义符( \ )本身,而且也只是只能,也就是说,单引号它的转义只能转义上面的两种情况,但是双引号的转义就更多了,比如双引号可以转义\n,\r之类的,单引号不能,如图:
在双引号定义的字符串中能使用的转义字符如下表所示:
-
-
字符串定界符
<<<之后提供一个标识符开始,然后是字符串的内容,最后是同样的标识符表示结束。
注意:结束标识符之后必须接分号;不可以用其他的任何字符,标识符的命名规则跟变量是一样的。<?php echo <<<str // html代码 str;
作用是为输出大量的文本提供简单的方法,开始和结束的定界符必须一样,名字跟变量的命名规则一样,随便起,单元遵循命名规范,以上相当于双引号字符串,如果是<<<‘str’ 有单引号的,那么它就相当于单引号,字符串定界符的优点是里面可以包括单引号,双引号,不需要转义。
易错点:
-
8.3.2 两种复合类型
-
数组
一个变量保存一个值,100个变量保存100个值,这不好记。我们可以吧这100个变量组合在一起,统一叫一个名字,然后各个元素用下标来区分,数组是计算机内部连续的空间,它跟变量不一样,各个变量都不是连续的,他们的位置随意,并不是我们控制的,比如,你定义了两个变量a和b,他们的位置并不一定紧挨在一起,如果把a和b放在一个数组中,那么他们就会紧挨在一起。数组又分为索引数组和关联数组。
索引数组:通过元素的位置做下标$stu=array('tom','berry','ketty'); //索引数组 echo $stu[0],"<br>"; // tom echo $stu[1],"<br>"; //berry echo $stu[2],"<br>"; //ketty
关联数组:
//格式:array(key=>value,key=>value...) $emp=array(‘name’=>'李白',‘sex’=>'男','age'=>20); //键值对 echo $emp['name'],'<br>'; echo $emp['sex'],'<br>'; echo $emp['age'],'<br>';
数组的值和一个字符串做关联,形成一个键值对。
数组当中的key,value,必须要用引号来包裹,单双引号都行,除了数字,和布尔值不用包裹,直接用除外。数组的声明2
$worker2[]='tom'; $worker2[]='berry'; print_r($worker2);
数组的声明3
$变量名 = [ 值1, 值2 , …]
易混点1
<?php $array=array(1=>'a','b','c','d'); //结果是往后索引都是1,2,3,4 print_r($array);echo '<hr>'; $array=array('a',2=>'b','c',5=>'d'); //结果是0,2,3,5 print_r($array);echo '<hr>'; $array=array('a',‘name’=>'b','c',‘sex’=>'d'); //结果是0,name,1,sex print_r($array);echo '<hr>'; $array=array(1=>'a',1=>'b',1=>'c','d'); //结果是Array([1]=>c [2]=>d) print_r($array);echo '<hr>';
易混点2
<?php $stu[true]='李白'; $stu[false]='杜甫'; $stu[12.9]='白居易'; $stu[-12]='辛弃疾'; $stu[-13.8]='王安石'; $stu["10"]='李清照'; $stu['']='苏东坡'; echo '<pre>'; var_dump($stu);
结果如下:
array(7) { [1]=> string(6) "李白" [0]=> string(6) "杜甫" [12]=> string(9) "白居易" [-12]=> string(9) "辛弃疾" [-13]=> string(9) "王安石" [10]=> string(9) "李清照" //将字符串数字转成整形做下标 [""]=> string(9) "苏东坡" }
我们发现,不管是正小数,还是负小数,都是取整数部分,负数是可以做下标的,空的也可以做下标,最后一点,如果我们把 $stu[null]=‘小苏东坡’;放在苏东坡的下面,我们就会发现小苏东坡把苏东坡给覆盖掉了,这就说明null转成了字符串""做下标。
数组的分类
按照元素的键值关系分为:索引数组(通过元素的位置做下标)和关联数组(通过字符串做下标,键和值存在某种关联)。
注意点:不能以前面的数字来判别是索引数组,如$stu=array(1=>‘tom’,2=>‘berry’);这是关联数组,其实关联数组和索引数组,计算机是不区分的,只是我们程序员这么分。
按照数组的结构分:一维数组和多维数组。数组的特点(区别于其他的编程语言)
1)PHP不需要在创建的时候指定数组的大小。
2)数组里面可以存任何类型的数据。预定义超全局数组变量
已经定义好了(存在)的变量(存放的数据的类型是数组)
超全局:超全局变量,跟全局(在后面"函数篇"会介绍到)不同的是,全局在函数外部定义,但是在函数内部要用global来访问,超全局就不用global来访问啦。它的作用域在一个脚本的全部作用域中都可用。
超全局变量总是以$_开头的, 比如$_GET,$_POST,还要注意的是所有的超全局变量的类型都是数组$GLOBALS $_SERVER $_GET $_POST $_FILES $_COOKIE $_SESSION $_REQUEST $_ENV
我们发现它们全是大写,是不是跟常量是一样的呢,而且常量也是在整个脚本都可以访问。所以,它们都大写意在告诉你们它们是超全局的。
当我们提交表单(提交注册页面),肯定会有数据的提交,比如名字,生日这些。提交个服务器端主要有两种方式,get和post。首先看看get方式,$_GET,比如:http://localhost/demo/index.php?参数名=参数值。那么我们在服务器端怎么通过参数名把参数值获取出来?假设参数名是name,参数值是小米。我们用$_GET就就可以把小米拿到。<?php var_dump($_GET); //这样就获取到了
想传多个可以用&隔开,比如:http://localhost/demo/index.php?参数名1=参数值1&参数名2=参数值2。
因为get的参数和值会暴露在地址栏上,不安全,所以为了安全,我们可以用post。
$_GET是保存get提交的数据,$_POST保存的是post提交的数据
新建一个xxx.php,记住,copy以下代码要粘贴到后缀为php的文件,不是后缀为html的文件,html文件是不支持php代码的,只有php文件才可以嵌入html代码<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <?php //第一次提交为空,显示array(0){} var_dump($_GET); ?> <!--action为空代表提交到本页面--> <form method="get" action=""> 姓名:<input type="text" name="username"><br/> 密码: <input type="password" name="pwd"><br/> <input type="submit" name="button" value="提交"> </form> </body> </html>
效果如下:
post的把上面get改为post自行测试
如果action要传参数怎么办,因为要提交到本页面,所以我们并没有再去新建一个php文件,就在本页面提交,所以上面的例子我们action为空,如果要传参,直接?属性名=值1&属性名=值2即可,类似<a href=“a.php?id=10&name=ketty”>,像这种html代码我们一定看的懂,它是提交到a.php页面的,并且传参过去,但是我们是提交到本页面,所以前面的如a.php可以不写,如果你理解了,那么以下的代码你应该看的懂。<?php //第一次提交为空,显示array(0){} var_dump($_REQUEST); ?> <!--action为空代表提交到本页面--> <form method="post" action="?add=北京"> 姓名:<input type="text" name="username"><br/> 密码: <input type="password" name="pwd"><br/> <input type="submit" name="button" value="提交"> </form>
注意以上代码为post提交,但是action表明的确实get提交(get提交要带有参数,post提交是不会显示参数的),那怎么办?注意,我上面的php代码不是$_GET,也不$_POST,而是$_REQUEST
所以,$_REQUEST,是即可以接受get请求,也可以接受post请求,所以,现在我们把$_GET,$_POST,$_REQUEST,是不是已经搞清楚了呢,
如果我们把上面图片的$_REQUEST搞定了,那么问题来了,如果get提交的参数是username,而post提交的参数也是username,那么$_REQUEST该怎么接收?
结果表明,username并不是小爱,而是小站,所以它是默认以post为准的。想改get为准也是可以的,只要改php.ini配置文件即可,定位到request_order=“GP”,表明先接收get再接收post,所以post把get给覆盖了,我们可以把它改为PG,这样,就是get把post给覆盖了。
写一下$_SERVER:<?php echo "你的ip是",$_SERVER['REMOTE_ADDR'],'<br/>'; echo '你的浏览器信息是',$_SERVER['HTTP_USER_AGENT']; ?>
-
对象
以后再讲。放在PHP面向对象哪章说。
8.3.3 两种特殊类型
-
资源(如数据库)
php引用的外部数据,称为资源。资源只能获取,不能创建、资源也是有类别的,比如连接资源,数据流资源。<?php $link=mysql_connect('localhost','root','aa'); var_dump($link); //resource
关于PHP连接数据库的后面在说。
-
NULL
表示没有一个变量没有值,NULL不区分大小写,同时,没有返回值的函数,返回的也是NULL。function fun(){}; var dump(fun()); //NULL
重点:为NULL的几种情况(总结)
- 根本就不存在的变量
- 将变量直接赋值为null
- 声明的变量尚未被赋值
- 被unset函数销毁的变量(被销毁后,变成第1种情况)
- 没有返回值的函数
8.4 伪类型
假类型,实际上在PHP中不存在的类型。但是通过伪类型可以帮助程序员去更好的查看操作手册从而方便学习。
- Mixed:混合的,可以是多种PHP中的数据类型。比如上面gettype()函数里的传的参数的数据类型就是Mixed。
- Number:数值的,可以是任意的数值类型(整形和浮点型)
9. 数据类型的相互转换
不同的数据类型在进行运输操作的时候,要注意类型的转换,类型转换分为自动转换和强制转换。
9.1 自动类型转换
我们做数学题,肯定不会出现像1+狗=?。这种题,以为他们压根就不是同一个东西,一个是数字,一个是字符,怎么相加?不过,在php当中,它会给你自动转换成同一个东西,就是同一个类型,这不是我们手动去告诉他转换的叫做自动类型转换。
情形一:if判断中
$num=10;
if($num){ // 请看后面的跟bool的转换规律
echo 'i am a boy';
}
结果是i am a boy。说明num为true,将数字自动转换为布尔型
情形二:数字运算
echo '10aa'+'20bb';
结果是30,因为php的加号只做数字运算,所以会把字符串转为数字
$num1='abc';
$num2=0;
if($num1==$num2){
echo '这两个数相等';
}
结果是相等,因为字符串’abc’转为数字是0。注意在数字运算中,只有字符串转为数字,不会数字转为字符串。
总结:自动类型转换的几种情况
- 有布尔值参与运算时,true将转化为整形1,false将转化为整形0。
- 有null值参与运算时,null值转化为整形0再进行运算。
- 有int型和float数据参与运算时,先把int转变成float类型后再进行运算。
9.2 强制类型转换
语法:(目标数据类型)数据
$num1=-12;
var_dump((bool)$num1); //bool(true)
echo '<br>';
$num2=12.5;
echo (int)$num2; //12
9.3 跟bool的转换规律
// 字符串和bool的转换规律
var_dump((bool)'abcd'); //true
var_dump((bool)''); //false
var_dump((bool)'0'); // false
var_dump((bool)'0.0'); //true
var_dump((bool)'00'); //true
var_dump((bool)'false'); //true
var_dump((bool)'null'); //true
//字符串转bool总结:字符串里面没东西为false,包括字符串0,因为字符串0会转为数字0,而数字0就是false
// 数字和bool的转换规律
var_dump((bool)1); //true
var_dump((bool)0); //false
var_dump((bool)-10); //true
var_dump((bool)1.1); //true
var_dump((bool)0.0); //false
var_dump((bool)-1.1); //true
//数字转bool总结:0为假,非0为真
// 数组和bool的转换规律
var_dump((bool)array()); // false
var_dump((bool)array(1)); //true
var_dump((bool)array(false)); //true
// 数组转bool总结:空数组为false
// null和bool的转换规律
var_dump((bool)null); //false
10. 常量
10.1 常量的简单概述
1.常量是一个简单值的标示符,如其名称所暗示的,在我们PHP脚本执行期间一个常量一旦被定义,就不能被改变或者取消定义,常量的作用域是全局的,常量只能包括bool,int,float,string类型的数据!注意,常量跟变量一样也是临时存储值的容器。
2.当一个数据在脚本执行的周期内不发生变化,可以将数据保存在常量中,常量前面没有$,语法是: define(常量名,常量值,是否区分大小写)。
10.2 常量的命名规则
命名规则跟变量一样,只不过变量名一般总是大写。
10.3 常量是否区分大小写
<?php
define('NAME','李白');
echo NAME,'<br>';
echo name,'<br>';
默认是区分的。
由此可看出,常量是默认区分大小写的,如果我要不区分大小写呢?不是还有第三个参数吗?
所以,第三个true表示不区分大小写,那默认就是false咯,false表示区分大小写。
10.4 声明常量的几种方式
声明常量的第二种方法:const
10.5 常量名如果含有特殊字符
定义常量可以用特殊字符,但是调用的时候。。。
发现报错了,那我该怎么调用不报错呢?哪就要用到一个关键字了,就是constant关键字。
<?php
define('^-^','李白');
echo constant('^-^');
这样就不会报错了。
10.6 重复定义常量
常量只能定义一次,一旦定义,是不能改的。
但如果,我并不知道这个常量前面有没有定义怎么办,这时候又有一个新的函数,谁呢?defined(‘NAME’)
NAME上面已定义,所以defined(‘NAME’)为true,但又取反,所以if判断不成立。
10.7 预定义常量(系统常量)
预定义常量就是预先定义好的常量,说白了就是我们的PHP内核已经帮我们定义好了的常量!供我们直接拿来使用。
10.7.1 预定义常量有哪些
显示所有预定义常量:
格式化是如果不格式化,它会显得非常乱,true表示将所有的常量分类显示.
以下显示比较常用的,了解一下即可:
PHP_VERSION // 当前的PHP服务器版本名
PHP_OS
PHP_SAPI
PHP_EOL
PHP_INT_MAX //整形能表示的最大值
PHP_INT_SIZE // 整形大小,输出4。表示整形所占的字节数,就是32位
__DIR__ // 当前被执行的脚步所在电脑的绝对路径
__FILE__ //当前被执行的脚步所在电脑的绝对路径(带自己的文件名)
__LINE__ //当前行数
__FUNCTION__ //当前的函数名
__CLASS__ //当前的类名
__METHOD__ //当前对象的方法名
M_PI //圆周率
........
其中有的预定义常量是以英文状态下的两个下划线(__)开头的,这些预定义常量我们又叫它魔术常量(系统魔术常量),用户是不可以改变的,因为它是常量。
10.7.2 魔术常量(不区分大小写)
魔术常量也是预定义常量,那什么是魔术常量呢?我们知道,常量是不变的,但是它有时候又像变魔术似的,它会变,代码所在的位置不同它的值也是不同的,这就是魔术常量。https://www.php/manual/zh/language.constants.predefined.php
11. 运算符
11.1 运算符的简单概述
就是一些符号,这些符号可以将变量或者数据执行某种运算。
运算符对一个或者多个操作数(变量或者数值)执行某种运算的符号,也称操作符。
!true // !是操作符,true是操作数
$a+$b // +是运算符,$a和$b是操作数
true?1:0 // ?和:是运算符 true,1,0是操作数
根据操作数的个数我们分为一元运算符,二元运算符,三元运算符。
注意:在php里面,加号(+)只能进行数学运算,只有点(.)才能进行字符串拼接。
11.2 算术运算符
算术运算符就是加减乘除这些。+,-,*,/,%,++,- -。
$a=1;
$b=2;
echo $a+$b; // 3
$c=1;
echo -$c; // -1
$d=10;
echo $d++; //10 后++;先返回变量的值,再去执行自增。相当于两句话,echo $d; $d=$d+1;
$e=10;
echo ++$e; //11 相当于 $e=$e+1;
11.3 字符串运算符
PHP中的字符串运算符只有一个英文的句号(.),也叫连接运算符。
<?php
$a = '小陈';
$b = '爱你们哟';
echo $a.$b; //结果是 小陈爱你们哟
echo $a.'爱你们哟'; //同样的效果
11.4 赋值运算符
赋值运算符就是等于号=,比如$a=1;就是把1赋给a。
除了=;还有+=, -=, *=, /=, %=, .= 。
11.5 比较运算符
对操作数进行比较。如果比较出来的结果满足比较运算符的要求那么结果就是true,否则就是false。
1) 值是否相等 ==
,相当于数学中的=,不比较数据类型。
2) 值和类型是否相等 ===
。
3) !=
值是否不相等。如果两边操作数的值不相等那么就是true。
4)<>
跟!=是一样的,也是不等于。
5)!==
,比较数据类型和值是否相等。
6)<
,小于。
7)>
,大于。
8)<=
,小于等于。
9)>=
,大于等于。
11.6 逻辑运算符
对表达式进行逻辑运算,运算结果也是true或false。
参与逻辑运算的表达式的值是布尔类型的值,如果不是布尔类型的值会被自动转换成布尔类型的值。那些会转为bool,请参考上面的数据类型的相互转换部分。
1) 逻辑与:and
或者&&
,两边为true,结果就为true。
2) 逻辑或:or
或者||
,两边只要有一个为true,结果就为true。
3) 逻辑异或:xor
,左右两边表达式的值不一样的时候就是true。就是一边是true,一边是false,哪结果就是true。
4) 逻辑非:!
,取反,原来是true,结果就是false,原来是false,结果就是true。
11.7 位运算符
位运算符用于对操作数中的每一个二进制位进行运算。
-
在前面我们已经弄懂什么是二进制(二进制就是0和1),所谓二进制,就是逢二进一,不管是哪门编程语言,运算都是以二进制来运算的。因为使用二进制只有0,1这两个数,简单,易于电子方式实现,同时,通过0,1的组合,可以表示任意一个数。现在我们要更加的了解好二进制,首先理解一下原码,反码,补码,我们精简了下面几句话:对于有符号而言:
- 二进制的最高位是符号位:0表示正数,1表示负数。
- 正数的原码(用二进制表示一个数,就是原码),反码,补码都一样。
- 负数的反码=它的原码符号位不变,其它按位取反(0->1 1->0)
- 负数的补码=它的反码+1
- 0的反码,补码都是0
- php没有无符号数,换言之,php中的数都是有符号的(表示最高位一定是一个符号,正和负)。无符号,就是没有正和负
- 在计算机运算的时候,都是以补码的方式来运算的,不管是正数还是负数
-
php中有4个位运算符,分别是"按位与&,按位或|,按位异或^,按位取反~",它们的运算规则是:
按位与&
:两位全为1,结果为1
按位与|
:两位有一个为1,结果为1
按位异或^
:两位一个为0,一个为1,结果为1
按位取反~
:0->1,1->0
上面的4个规范:在哪个编程语言都适用,它不是只在php这里才能用。 -
练习:
注意:一定是补码进行运算,不管你是什么运算,与也好或也好。按照上面的7条规范做。上面的,补码的运算还是补码,但是看结果还得看的是原码,不要以为把补码算出来就好了,最终还要逆推回去。
移位运算
就是对二进制数进行移动,要么是左移,要么是右移。
-
算术右移>>
低位溢出,符号位不变,并用符号位补溢出的高位。
-
算术左移<<
符号位不变,低位补0。
负数的就不用演示了。。。
左移规律:
发现了什么规律?是不是每移一位就会乘以一个2。
11.8 其它运算符
1) ?:
简单的分支结构缩写。
$num=20;
echo $num%2==0?'偶数':'奇数'; //如果成立,就是偶数,不成立,就是奇数。
2)`` 可以把系统的命令放在里面执行,比如,我们会在cmd命令窗口里面输入ipconfig,然后就会在命令行里显示,我们也可以让它在php编辑器里显示,如下代码:
<?php
$info = `ipconfig`;
echo $info;
3) @,屏蔽错误
12. 运算符的优先级
谁的优先级高,先算谁。知道一些就可以了。
以下便是优先级由高到小排列:
1)[无] 递增递减
2)[右] 逻辑非!
3)[左] * / %
4)[左] + - .
5)[无] 包含大于号或者小于好的比较运算符
6)[无] 不包含大于号或者小于好的比较运算符
7)[左] &&
8)[左] ||
9)[左] 三元运算符?:
10)[右] 赋值运算符
11)and
12)xor
13)or
注意,[左]表示从左往右运算。像&&和and功能一样,但优先级不一样,有括号先算括号里面的。
13. 流程控制
13.1 流程控制的简单概述
对PHP程序的执行过程进行控制
执行顺序分为顺序执行,分支执行
1)顺序执行就是从上到下依次执行。
2)分支执行就是我们可以根据条件来满足是否选择执行某种代码。PHP的分支执行主要有两种if,switch。
13.2 单分支
如下代码:
if(条件){
// 代码块
}
如果条件成立就执行代码块,条件不成立就不执行
如果if块中就一句代码,则大括号是可以省略的。for也一样。
13.3 双分支
<?php
if(条件){
//代码1
}
else{
//代码2
}
如果条件成立就执行代码1,条件不成立就执行代码2
13.4 多分支
多分支是elseif,注意elseif不能写成else if(加空格不是多分支),中间没有空格。
if(条件1){
}
elseif(条件2){
}
else{
}
13.5 多路判断switch
switch(表达式){
case 值1:
语句块1;
[break]; //可以省略,只不过它会继续向下执行,跳过下面的判断。
case 值2:
语句块2;
[break];
case 值3:
语句块3;
[break];
..........
default:
语句块n
}
13.6 替代语法
单分支的替代语法
替代语法 :左大括号变冒号,右大括号变endif;如果是for,就是endfor;如下
<?php
if(20>10):
echo 'success';
endif;
双分支的替代语法
<?php
if(条件):
//代码1
else:
//代码2
endif;
多分支的替代语法
if(条件1):
//代码1
elseif(条件2):
//代码2
else:
//代码3
endif;
14. 循环执行
当一段代码需要多次重复执行,就需要用到循环。索引数组可以用for遍历,但是关联数组不行。
14.1 for
for(初始值;条件;增量){
}
在一个循环了N次的循环中,初始值执行了几次?条件执行了几次?增量执行了几次?
答:初始值执行1次,条件N+1次,增量N次
for($i=1;$i<5;$i++){
}
echo $i; //输出6
for循环结束后,$i变量还是存在的
输出所有可见ASCII码字符:
可见字符的ascii码是从32-126之间
for($i=32;$i<=126;$i++){
echo chr($i),' ';
}
for($i=1,$j=9;$i<=$j;$i++,$j--){
echo 'xxx';
}
//在第二个参数时,也就是条件哪一块,后面的条件把前面的条件覆盖掉
for($i=1,$j=9;$i>$j,$i<=$j;$i++,$j--){
echo 'xxx';
}
14.2 while
while(条件){
}
替代语法:
while(条件):
endwhile;
14.3 do-while
do{
}while(条件);
do-while和while的区别是dowhile至少会执行一次。
明确知道循环多少次,首选for循环,不知道循环多少次,一直循环到条件不成立为止,选while和do-while,while先判断再执行,do-while先执行后判断。
14.4 foreach
作用:遍历数组(索引数组和关联数组)
$stu_array=array('李白','杜甫','白居易');
foreach($stu_array as $stu){
echo $stu,'<br>';
}
foreach($stu_array as $key=>$stu){
each $key,'-',$stu,'<br>';
}
最后foreach也支持传引用,比如在$stu前面加上&。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<?php
if(isset($_POST['button'])){
if(empty($_POST['hobby'])){
echo '你太内向了';
}else{
$hobby=$_POST['hobby'];
echo sizeof($hobby),'<br>'; //获取数组长度,sizeof(),当然,count()也可以
/*for($i=0;$i<count($hobby);$i++){
echo $hobby[$i],'<br>';
}*/
// 以上效率不高,每循环一次数一次,说白了就是每循环一次,count()函数就要执行一次,数来数去还是一样的
for($i=0,$n=count($hobby);$i<$n;$i++){
echo $hobby[$i],'<br>';
}
}
}
?>
<form method="post" action="">
爱好:
<input type="checkbox" name="hobby[]" value="爬山">爬山
<input type="checkbox" name="hobby[]" value="读书">读书
<input type="checkbox" name="hobby[]" value="游泳">游泳
<input type="submit" name="button" value="提交">
</form>
</body>
</html>
15. break和continue
break:中断循环。默认情况下break中断的是当前循环,如果想要中断多重循环,需要在break后面加上需要中断循环的层数(break 数字),break可以用于switch语句,for,while,do…while,foreach,用于中断这些语句。
continue:跳槽当前循环,进入下一个循环。continue后面也可以带数字,表示要跳出的层次。
在什么情况下,break和continue的作用是一样的?
当我们只循环一次的时候一样。switch本质就是循环一次的循环,所以break换成continue是一样的。
for($i=1;$i<=10;$i++){
switch($i){
case 5:
break 2; //跳了两次循环,考查switch本质也是循环
}
echo $i,'<br>';
}
扩展:goto,goto它也是跳出的意思,具体看代码:
for($i = 0; $i < 10; $i++) {
if($i == 4){
goto a; //当它遇到这条语句的时候,它会跳到第7行,向下执行。
}
echo $i;
}
a:
echo "跳出循环";
16. PHP的执行过程
16.1 认识内存
首先,要明白,内存是php执行代码,运行的一个载体,而且在上面我们也说了内存就相当于我们计算公式的那张纸,那么内存它分为几种结构?我们大概了解一下:
- 内存结构:
- 栈区:
保存的是变量名(引用)。
对应cpu来说,读写速度是最快的。 - 堆区:
保存的是复杂数据。复杂数据比如数组,它是一个变量保存多个值,一对多,可以理解为复杂数据。还有对象,字符串。 - 数据段:
保存的是简单数据。简单数据比如int啊,浮点型,布尔型,这些它不像数组,它是一对一的。它保存在全局区。注意字符串不存在数据段里。静态区存的是静态变量和常量。 - 代码段:
存储的是源代码对应的机器指令。(转化为机器看的懂的指令) - 输出缓存:
只要遇到输出命令,例如echo,print,print_r,var_dump,这些指令都会将所要输出数据放在输出缓存中。
- 栈区:
16.2 php的执行过程
- 编译阶段:
进行语法检查,词法检查,代码优化。编译通过之后将源代码转化为机器指令。 - 执行阶段:
如果编译通过后,会将源代码对应的机器指令,保存在代码段,再开始执行代码段中的机器指令。
16.3 php嵌入到HTML的执行过程
当php功能模块在处理一个php文件时,它只关心php代码(使用php标签包含的代码),其它自动返回,原样输出,输出到哪,输出到缓存中。比如html代码,php关心吗?不关心。当在执行php代码段中,遇到echo这种输出语句,也一样会输出到缓存中。把echo 要输出的字符串内容一成不变的输出到缓存中,比如你可以输出html代码,再交给apache,apache再交给浏览器解析。对于php来说,它看到的都是字符串。如下代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<?php
echo '<script>alert("我是在php里的弹框")</script>'
?>
<script>alert("我是在html里的弹框")</script>
<!--上面php里的代码跟下面这个直接写在html的js代码有区别吗?没有吧,效果是一样的,
其实这也能说明了php在执行过程中遇到echo 后的字符串里的数据会原样的输出到html当中。-->
</body>
</html>
好,我们发现查看网页源代码是它居然没有换行,说明了php根本没解析<br>这个标签,这就更充分说明了,php它只是单纯的输出里面的字符串,它不会管你里面有没有什么html标签,在它眼里,你就是一个字符串。我只管输出即可。但也不排除有转义字符,比如\n,php是不会原样输出的。如何解决源代码在一行的问题,如下代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<?php
for($i=1;$i<=10;$i++){
?>
<?php echo $i?>:hahahaha<br>
<?php
}
?>
</body>
</html>
总结:
客户端向服务器端发送请求,服务器会解析PHP代码生成一个标准HTML代码,将HTML代码发送到客户端,客户端解析HTML代码生成我们看到的页面。
17. 函数
17.1 何为函数
函数是一个固定的代码块,或者称为一个子程序,一个函数可以多次调用,函数实现了计算机模块化的模块化编程,它分为自定义函数和系统函数(内置函数)。
17.2 自定义函数
17.2.1 函数的定义
1.函数的定义
function 函数名([参数1,参数2,...参数n]){ //函数名的命名跟变量命名一样
函数体; //任何有效的PHP代码都可以作为函数体使用
return 表达式; //可以从函数中返回一个值,也可以不返回
}
注意:函数名是不区分大小写的,如abc和AbC它会认为是一个函数。
17.2.2 函数的调用
不管是自己定义的函数,还是系统提供的函数;如果函数不被调用就不会执行!
调用:函数被调用后开始执行函数体中的代码,执行的过程是相对独立的,执行完毕返回调用的位置继续向下执行!
function test(){
echo '你好!';
}
test(); //这就是函数的调用,调用一次会在内存开辟一个空间供你运行。
test(); //跟第一个调用无关,这是另一个空间。
PHP的骚操作:函数调用也可放在前面
test(); //依然可以
function test(){
echo '你好!';
}
以上其实是函数的预加载,在你调用test()的时候就已经加载进去了。就是在你执行之前,函数就已经加载进内存当中了。是这么一个过程:编译->加载编译的代码->执行。
要想跟深入的了解函数的调用流程,可以看递归函数。
17.2.3 函数的参数
函数的参数分为形式参数和实际参数。形式参数由零个,一个或者多个变量组成。实际参数由零个,一个或者多个参数组成,每个参数是一个表达式,用逗号分隔。并且数据类型可以是任意的类型,只要是php支持的类型(八大)。
function add($a,$b){ //形式参数,就是一个形式,因为他们里面没有具体的值!
echo $a+$b;
}
add(2,3); //实际参数
add(2,3,4); //多传的4会被忽略掉
17.2.4 函数的返回值
函数的返回值是将函数执行后的结果返回给调用者!不写默认返回null(return null;)。
function add($a,$b){
return $a+$b;//返回值给调用的地方,结束这个函数的运行!
}
var_dump(add(10,20));
17.2.5 匿名函数
php从5.3开始支持匿名函数,匿名函数就是没有名字的函数,匿名函数保存在变量中
$fn=function($args){
echo $args;
};
var_dump($fn); //object(Closure)
echo '<br>';
$fn('i am a boy'); // i am a boy
Closure就是闭包,注意:匿名函数不一定是闭包,但闭包一定是匿名函数。
17.2.6 可变函数(变量函数)
就是把一个函数赋给变量。
<?php
function test(){
echo '我是test函数!';
}
$a='test';
$a();
18. 变量的范围
18.1 局部变量
局部变量也称为内部变量。局部变量是在函数内定义的,其作用域仅限于函数内部,离开该函数后再使用这种变量就是非法错误的。
function test(){
$a=1; //局部变量$a只在这个函数内有效。
}
echo $a; //错误
总结:一个自定义函数中的变量是局部的,函数外不生效。
18.2 全局变量
全局变量也称为外部变量,在函数的外部定义的,它的作用域为从变量定义处开始,到本程序文件的末尾。
在PHP函数中无法直接使用全局变量,如需使用必须使用global声明变量!注意global拿到的是变量的地址
<?php
$a=5;
function myTest()
{
global $a;
echo $a; //也可以直接写成echo $GLOBALS['a'];
}
myTest();
?>
18.3 静态变量
静态变量是指在函数内部定义变量的时候使用static关键字来定义变量,
函数执行完毕之后变量不会立即消失,当再次调用函数时,静态变量保存值依然存在,并且仅在第一次执行函数的时候初始化!
function test(){
static $a = 10; //静态变量$a,初始化静态变量,尽在第一次调用的时候执行。脚本执行程序才销毁。
echo ++$a; //当第二次执行这个函数的时候$a这个变量依然存在并且里面的值也依然存在
}
test(); //11
echo '<br/>';
test(); //12
19. 参数传递(按值传递和按引用传递)
19.1 按值传递
只要是参数传递就会有两种,一种是传值(两个空间),一种是传地址(一个空间),我们在传递参数的时候默认使用的就是按值传递。
function test($a){ //取变量的值
echo ++$a; //11
}
$i=10;
test($i);
echo '<br>'.$i; //10,对形式参数的操作,根本不会影响到实际参数的值,两者相当于没联系!
<?php
function fun($args){
$args='这是一个字符串';
}
$stu=array('tom'.'berry');
fun($stu);
var_dump($stu); // 打印的是数组,因为它传的是值
19.2 按引用传递
function test(&$a){ //加上&表示取变量的地址
echo ++$a; // 11
}
$i=10;
test($i);
echo '<br>'.$i; // 11
<?php
function fun(&$args){
$args='这是一个字符串';
}
$stu=array('tom'.'berry');
fun($stu); //注意:只有变量才可以传地址,字符串不能如fun('aa')
var_dump($stu); // 打印的是字符串,因为它传的是地址
函数的默认参数
<?php
function test($a=10){
echo ++$a;
}
test(); //不传参,可以,因为有默认值。传的话就按你传的来。
function test($a,$b=10){ //不能给$a和$b调换顺序,不然下面的20不知道传给谁。
echo $a+$b;
}
test(20);
接收多个参数
<?php
function test(...$args){
print_r($args);
}
test(21,343,56);
?>
20. 递归函数(可以理解函数调用的过程)
递给函数即在函数内部自己调用自己的函数。
<?php
function test($n){
echo $n.' ';
if($n>0){
test($n-1); // 自己内部调用自己,即递归函数。
}else{
echo '<-->';
}
echo $n.' ';
}
test(3);
最终结果:3 2 1 0<–>0 1 2 3
函数在被调用的执行过程中会在内存里面分配空间用于存储临时数据,那么函数在执行过程中默认之间是没有联系的(除了静态变量,按引用传,全局变量)。里面的变量默认都是局部变量,相互之间没有影响。在使用递归的时候要有条件让它结束,不然会不断分配空间,变成死循环了。
总结
1. 函数执行的规则,只要一看到函数,则php就会开辟一个新栈(空间)。
2. 各个栈间的变量是相互独立。
3. 一个函数一个栈
21. 内置(内部)函数
PHP提供给我我们许多现成的函数或者结构,我们可以在实际的开发中直接使用!比如,数组,字符串,我们PHP提供了大量的函数去操作这些数据类型。
echo()
include()
include_once()
require()
require_once()
上面这些它们可以省略括号使用,严格意义上讲不上函数,所以这些不可以赋值给另外的变量,当然是不是函数不重要,对应我们的实际开发没有什么影响,我们的重点是知道这些能够为我们做什么工作!
还有一些函数需要开启特定的PHP扩展模块,否则在使用它们的时候就会得到一个致命的"未定义函数"错误。
21.1 获取变量的类型
gettype(传入一个变量):能够获得变量的类型
21.2 字符串处理函数
1)trim:去除字符串首尾处的空白字符(或者其它字符)。
格式:string trim(string $str [,string $charlist])
<?php
$str=' abcabcdef ';
var_dump($str); //结果就是abcabcdef。
$str='abcabcdef';
var_dump($str);
var_dump(trim($str,'a')); //结果是bcabcdef,a就去掉了
var_dump(trim($str,'ab')); //结果是cabcdef,表示你既要去除左右两边的a,还要去除左右两边的b,写成ba也是可以的,跟顺序无关。要注意上面,它去掉左边的a和b后,发现下一个是c,不是它要去除的对象,它就停止往后面去了,即使c的后面是a。
$str='abcabcdefac';
var_dump($str);
var_dump(trim($str,'bac')); //结果是def。
2)ltrim:去除字符串左边的空白字符(或者其它字符)。
3)rtrim:去除字符串右边的空白字符(或者其它字符)。
4)strtoupper:转换为大写
$str = 'test';
var_dump(strtoupper($str)); //结果是TEST
5)strtolower:转换为小写
6)substr_count:
格式:int substr_count(string $haystack,string $needle [,int $offset = 0[,int $length]])
$str='testtest';
var_dump(substr_count($str,'te')); int 2 //连续输出的te有多少个,而且不会重叠计算,比如gcdgcdgcd,我们要算gcdgcd有多少个,是先从前面的开始,前面的gcdgcd算完了就被干掉了。
//它还有第三个参数,如果是1,表示从索引为1的开始找。如:substr_count($str,'te',1),还有第四个字符,表示你要搜索几个。
7)strpos:查找字符串首次出现的位置。
格式:int strpos(string $haystack,mixed $needle [,int $offset = 0]);
解读:haystack表示被查找的字符串,needle表示你要找的那个字符串。找到返回索引值,没找到就是false。
<?php
$str='testteste';
var_dump(strpos($str,'t1')); //返回false
//下面是错的
if(strpos($str,'t')){ //这样是不行的,因为它返回的是索引0,而0又会被转换为false,所以明明是找到的,被变成没找到,这点要把它变成strpos($str,'t')===false;就可以了。注意是全等,虽然0会转为false,但他本质还是int类型。
echo '找到啦!';
}else{
echo '没找到!';
}
//下面这才是对的
if(strpos($str,'t')===false){
echo '找到啦!';
}else{
echo '没找到!';
}
$strr = 'testtestte';
var_dump(strpos($strr,'t',1)); //答案是3。第三个参数表示从索引1开始找,看看有多少个t
8)strrpos:查找字符串的最后一次出现的位置。
$str='abcda';
echo strpos($str,'a'),'<br>'; // 0
echo strrpos($str,'a'),'<br>'; // 4
9)strstr:查找字符串的首次出现。 跟刚才那个strpos,strpor只是输出位置。直接看代码,懒的解释了:
<?php
$str = 'testteste';
var_dump(strstr($str,'t')); //表示从索引0开始就找到那个t,既然找到了,那么它就会把后面的整个都给你返回出来。所以答案是testteste。
//它还有第三个参数,如果为true,返回前面的部分。
$str = 'testteste'
var_dump(strstr($str,'s',true)); //答案是te。不加true,就是默认的,答案是stteste
10)str_replace:字符串替换函数。直接看代码:
<?php
$str = 'testteste';
var_dump($str);
var_dump(str_replace('t','T',$str)); // 输出 TesTTesTe
//还可以传数组,如下:
$strr = 'abc123abc';
var_dump(str_replace(array('1','2','3'),array('一','二','三'),$strr);
//它还有第四个参数为$count;如下:
var_dump(str_replace(array('1','2','3'),array('一','二','三'),$strr,$count);
echo $count; //答案是3,因为它替换了3个。
//如果$str为数组呢,那么数组里的每一个元素都会被替换,如下图:
<?php
$str="小明是我的朋友,小爱也是我的朋友";
echo str_replace(array('小明','小爱'),'你',$str),'<br>'; //你是我的朋友,你也是我的朋友
$str1='你我它';
echo str_replace(array('你','我'),array('我','他'),$str1);
//结果是"他他它",并不是"我他它"。第二次的替代会在第一次的替代基础之上再替代
11)[]:字符串可以理解成字符的集合,所以可以通过[]来访问,不能操作中文,如下:
<?php
$str='abcdefg';
echo $str[0].'<br>'; //a
echo $str[1].'<br>'; //b
$str[3]='A';
echo $str; //abcAefg
12)strlen():返回字符串长度,以字节为单位。
<?php
echo strlen('ab').'<br>'; //2
echo strlen('你好');//6 如果是UTF-8编码的一个中文三个字节,在gbk下一个中文2个字节
13)str_repeat():重复字符串
<?php
$word="hello!";
echo str_repeat($word,3);//hello!hello!hello!
14)str_pad():字符串填充
<?php
$stuid=12;
echo str_pad($stuid,4,'0');//默认是右填充 //1200
//第四个参数是表示是左填充(STR_PAD_LEFT),还是右填充(STR_PAD_RIGHT),还是平分填充
echo str_pad($stuid,4,'0',STR_PAD_LEFT); //0012
echo str_pad($stuid,4,'0',STR_PAD_BOTH); //0120
15)nl2br:将字符串的换行转成<br>
我们发现我在文本框中写的故事是有换行的,格式如上。但是我一提交到后台,却是在一行显示,那要怎么解决这问题呢?很简单,加上nl2br函数。如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<?php
if(isset($_POST['button'])){
echo nl2br($_POST['str']);// 将\n换成br
}
?>
<form method="post" action="">
<textarea name="str" rows="5" cols="20"></textarea>
<input type="submit" name="button" value="提交">
</form>
</body>
</html>
16)urlencode和urldecode:url的编码和解码
<?php
$code=urlencode('你好呀');
echo $code,'<br>';
echo urldecode($code);
?>
21.3 与html标出相关的函数
1)htmlspecialchars():函数把一些预定义的字符转换为HTML实体。
预定义的字符是:
&(和号) 成为 &
"(双引号) 成为 "
'(单引号) 成为 '
<(小于) 成为 <
> (大于) 成为 >
查看网页源代码:
比如一个表单内让用户填内容,那个用户呢填了一个html标签在里面,然后他一提交过来,在页面上展示,这就不太好,会对页面的布局破坏,我们应该让用户提交过来的原封不动的输出在浏览器上,所以就是为了防止html在页面上得到解析。
它有第二个参数,默认是ENT_COMPAT(这个默认是仅编码双引号),而ENT_QUOTES:它就会编码双引号和单引号。ENT_NOQUOTES(不编码任何引号),如下图:
第三个参数是字符集。
2)strip_tags():从字符串中去除HTML和PHP标记,注释是干不掉的。直接看代码:
直接就把html标记给干掉了。
如果想留多个,就连着写,如"<div><p>"
3)substr():字符串截取函数,返回字符串的子串,看代码:
<?php
$str = "testhahahahaha";
echo substr($str,1);//结果是:esthahahahaha。表示从索引为1的开始剪,包括索引1,所以t被干掉了。
//第三个参数表示截几个。如果第二个参数是负的,假如是-3,那就是从后面开始截,后面第一个表示-1,从右往左截三个,比如test就是est,没有-0这东西。
//第三个参数如果为负数,表示后面几个字符不截取,如下:
$str1="abcdef";
echo substr($str1,2,-1),'<br>'; //cde
echo substr($str1,-4,-2); //cd
4)strchr():如下代码
<?php
$str="abcba";
echo strchr($str,'b'),'<br>'; //bcba
echo strrchr($str,'b'); //ba 可截取一个路径的后缀,比如.html,.jpg。第二个参数就是点。
5)explode():字符串分割函数。使用一个字符串分割另一个字符串。
6)str_split():将一个字符串转化为数组。
<?php
$str = 'test';
var_dump(str_split($str));
//结果是:array(4) { [0]=> string(1) "t" [1]=> string(1) "e" [2]=> string(1) "s" [3]=> string(1) "t" }
21.4 处理数组的相关函数
处理数组的相关函数是很多的,我们只是例举几个而已。
1)array_count_values:统计数组中所有的值出现的次数。
格式:array array_count_values(变量名)
<?php
$array = array(1,"hello",1,"world","hello");
print_r(array_count_values($array)); // Array=([1]=>2 [hello]=>2 [world]=>1) 以值做为键,出现的次数作为值。
2)array_key_exists:检查给定的整数和字符串是否存在数组中做为索引值。
格式:bool array_key_exists(mixed $key,array $search)
<?php
$search_array = array('first' => 1,'second'=>4);
if(array_key_exists('first',$search_array)){ //答案是true
echo "The 'first' element is in the array";
}
3)array_search:在数组中搜索给定的值,如果成功则返回相应的键名。
格式:mixed array_search(mixed $needle,array $haystack[,bool $strict])
解读:在haystack中搜索needle参数并在找到的情况下返回键名,否则返回false。
注意:第三个参数是可选的,当它为true,则array_search()还将在haystack中检查needle的类型。
<?php
$array = array(0 => 'blue',1=>'red',2=>'green',3=>'red',4=>15);
var_dump(array_search('green',$array)); //返回int 2
var_dump(array_search('15',$array,true)); //返回false。 第三个参数如果不写true,那么它就不比较类型,15跟'15'是一样的。
4)count:返回数组的长度,count(数组变量名)
5)in_array:检查数组中是否存在某个值,存在就返回true,不存在返回false。
格式:bool in_array(mixed $needle,array $haystack[,bool $strict])
解读:道理跟array_search是一样的。
6)list:此处不解释,直接看代码。
<?php
$arr = array(60,40,32);
list($xiaochen,$xiaoming,$xiaoai) = $arr;
echo $xiaochen; //输出60
//list只能用于索引数组
//注意,它是从左往右赋的,看下面代码:
list($arr[],$arr[],$arr[]) = array(60,40,29);
print_r($arr); //Array([0]=>29 [1]=>40 [3]=>60)
//list()从最右边一个参数开始赋值,如果你用单纯的变量,不用担心这一点,但是如果你用了具有索引的数组,通常你期望得到的结果和在list()中写的一样是从左到右的,但实际上不是,是以相反顺序赋值的。
7)asort:对数组进行排序并保持索引关系
<?php
$students=array(
'xiaochen' => 60,
'lilei' => 80,
'hanmeimei' => 100,
'zhangsan' => 90
);
var_dump(asort($students)); //排序成功返回true
扩展:保持索引关系是什么意思呢?如下:
<?php
$sum=array(100,25,85,68,45);
asort($sum);
print_r($sum);
?>
输出结果是:
Array ( [1] => 25 [4] => 45 [3] => 68 [2] => 85 [0] => 100 )
是不是索引和值一一对应?
扩展:
注意上图,有的是按键排序,有的是按值排序,注意分辨。
8)array_reverse:返回一个单元顺序相反的数组。
格式:array array_reverse(array $array[,bool $preserve_keys])
<?php
$students=array(
'xiaochen' => 60,
'lilei' => 80,
'hanmeimei' => 100,
'zhangsan' => 90
);
print_r(array_reverse($students)) //答案很显然,翻转了,zhangsan排在第一个了,依次是hanmeimei...
9)array_filter:用回调函数过滤数组中的单元。
格式:array array_filter(array $input [,Callback $callback])
解读:依次将input数组中的每个值传递到callback函数。如果callback函数返回true,则input数组的当前值会被包含在返回的结果数组中。数组的键名保留不变。
10)array_sum:求出数组的和。
11)range(起始值,结束值):生成一个指定范围的数组。
<?php
$array = range(10,20); //生成一个10-20的数组,包括10和20
print_r($array);echo '<br>';
$array1 = range('a','z'); //生成一个a-z的数组
print_r($array1);echo '<br>';
$array2 = range('A','Z'); //生成一个A-Z的数组
print_r($array2);echo '<br>';
$array3 = range('Z','A'); //生成一个Z-A的数组
print_r($array3);
?>
12)array_merge():上面的ranges是不是只能生成一个数组里是1到100,a到z这种连续的东东,如果我一个数组里即要有数字和字符怎么办?
<?php
//生成字母,数字,下划线的数组
$array=array_merge(range('a','z'),range('A','Z'),range(0,9),array('_'));
print_r($array);//他们合并在一起,索引被重写了,从0开始。
echo '<hr>';
$array1=array('name'=>'李白','sex'=>'男',0=>'a',3=>'c');
$array2=array('name'=>'杜甫','add'=>'北京',0=>'a');
$array3=array_merge($array1,$array2);
print_r($array3);
//数组合并时候下标冲突,如果是字符串为索引,后面的会把前面覆盖,数字为索引,索引会重建,结果如下图:
?>
13)array_rand:随机取出元素的个数,随机取出数组内元素,返回随机数组的下标。
注意:如果随机取出1个,返回整形下标,多个才是数组。 还有一个问题就是我们发现上面随机取出4个不管你测试多少次,它总是从小到大的排列,不信你们可以试试看。要想解决,请看下一个函数。
14)shuffle(数组):打乱数组,打乱成功返回true,否则返回false。
//验证码功能
<?php
$array=range('a','z');
$index=array_rand($array,4);
$str="";
foreach($index as $i)
{
$str.=$array[$i];
}
echo $str;
15)array_keys(数组):返回数组中的所有键名。
16)array_values(数组):返回数组中的所有值。
<?php
$stu=array('name'=>'小新','sex'=>'男','age'=>20);
$key=array_keys($stu);
$values=array_values($stu);
print_r($key);
echo '<br>';
print_r($values);
17)array_combine(键数组,值数组):上面中的结果是两个数组,就名字是小新哪个。如果我想把上面的两个数组一一对应,就是name跟小新对应,sex跟男对应,age跟20对应,改怎么办呢?。
<?php
$keys=array('name','sex','age');
$values=array('小新','男',20);
$array=array_combine($keys,$values);
print_r($array);
18)implode: 将数组的值连接成字符串。直接看代码:
19)array_diff: array_merge是数组的并集,那这个函数就是差集,什么是差集?格式:array_diff($array1,$array2),意思就是对比返回在array1中但是不在array2及任何其他参数数组中的值。
20)array_intersect:该函数是取两个数组的共同部分,交集。
21)array_map(函数名,数组):支持一次处理多个数组,如下代码:
上面的函数是PHP自带的函数,我们也可以使用我们自定义的函数,如下代码:
<?php
$stu=array('小飞','小马','小熊','小陈');
function fun($name){
return '你好'.$name;
}
$new_stu = array_map('fun',$stu);
print_r($new_stu);
//上面的函数只要一个参数,如果我想有两个函数怎么办?
//例子:比如我们求成绩总和,小米它的语文成绩是93,数学成绩是65,英语成绩是77
//小刚它的语文成绩是80,数学成绩是99,英语成绩是45
//我们知道两位同学它的3科的成绩,分别是语文,数学,英语,现在我想求它们语文成绩的总和,
//数学成绩的总和,英语成绩的总和,用array_map怎么实现呢?
$xiaomi=array(93,65,77);//小米的三科成绩
$xiaogang=array(89,99,45);//小刚的三科成绩
//求各个学科总和
function fun1($xiaomi,$xiaogang)
{
return $xiaomi+$xiaogang;
}
print_r(array_map('fun1',$xiaomi,$xiaogang));
//最终结果Array ( [0] => 182 [1] => 164 [2] => 122 )
22)指针函数:
1. reset():重置指针,将数组指针回到首位。
2. end():重置指针,将数组指针指向最后一位。
3. next():指针下移,取得下一个元素的值。
4. prev():指针上移,取得上一个元素的值。
5. current():获取当前指针对应的元素值。
6. key():获取当前指针对应的下标值。
23)栈和队列的相关函数:
栈和队列都是一致数据结构,栈是一个水杯,水杯有什么特点?它是不是有底,那么放入一个A石头,再放入一个B石头,再放入一个C石头,3个石头依次放入,当你想把A石头取出时,你肯定会拿出C石头,再拿出B石头,最后才拿到A石头,对不对?很好想嘛!队列就是一个水管,一通到底,谁先进去,谁先出来,比如有一个空心管道,你往里面依次放入弹珠,肯定是先进去的最后先出来。这就是占和队列的区别!!!
下面这幅图说明了unset销毁不会去重排索引。
array_push()和array_pop()作用在于维护一个连续的存储空间。
array_shift()是从第一个开始删除的。类似于队列。
<?php
//此处是队列结构函数
$stu=array();
array_push($stu,'小爱');
array_push($stu,'小明','小飞');
print_r($stu);
echo '<br>';
array_shift($stu); //出队列
print_r($stu); //Array ( [0] => 小明 [1] => 小飞 )
?>
array_shift()是从头部开始删除,那么array_unshift()是从头部添加的,跟push相反。
24)array_chunk:数组的拆分:
25)array_splice:把数组中的一部分去掉,并用其他值取代
21.5 判断是否为某种类型
1)is_string(变量) 判断是否为字符串
2)is_numeric(变量) 判断是否为数字字符串
3)is_scalar(变量) 判断是否为标量
4)is_int(变量) 判断是否为整形
5)is_float(变量) 判断是否为浮点型
6)is_array(变量) 判断是否为数组
7)is_object(变量) 判断是否为对象
8)is_resource(变量) 判断是否为资源
21.6 判断变量是否为空
在处理一个没有定义的变量时会报错,所以在处理变量之前,我们先要判断一下变量,判断的函数常用如下两个
函数 | 说明 |
---|---|
isset() | 判断变量是否有值,并且值不为null |
empty() | 判断变量是否为空 |
isset()
isset()可以向括号中间传入一个或者多个变量,变量与变量间用逗号分开。只要有有一个变量为null,则返回false。否则,则返回true。
empty()
总结:empty()判断中只要能转成布尔值为false的都是true。
isset不能去判断一个数组是否为空,只能用empty去判断一个数组是否为空,注意区别
isset()与empty()的区别是什么?
isset是判断变量是否存在,可以传入多个变量,若其中一个变量不存在则返回false。empty是判断变量是否为空,false,0等,是则返回true,否则返回false,只能传入一个值。
21.7 与二进制相关的函数
php提供了一些函数用来做进制转换:首先,先记住下表的缩写
进制 | 缩写 | 单词 |
---|---|---|
十进制 | dec | decimalist |
八进制 | oct | octonary |
二进制 | bin | binary |
十六进制 | hex | hexadecimal |
这样函数就好记了,如以下:
echo decbin(9),'<br>'; //将十进制九转为二进制
echo bindec(1001),'<br>'; //将二进制转为十进制
echo decoct(10),'<br>' ; //将十进制转为八进制
21.8 数学函数
- max(值1,值2…):返回参数中最大的值
- min(值1,值2…):返回参数中最小的值
- rand():返回0到RAND_MAX之间的随机整数,例如想要5到15(包括5和15)之间的随机数,用rand(5,15)
- mt_rand():与rand一样,只是底层结构不一样,效率比rand高(建议使用)
- round():四舍五入
- ceil():向上取整,比如4.3。那么比4.3大的最小整数是谁?哪就是5
- floor():向下取整,比如4.3。那么比4.3小的最大整数是谁?哪就是4
- pow():求指定数字的指定指数次结果,比如pow(2,8)表示2的8次方,即28
- abs():绝对值
- sqrt():求平方根
21.9 可变长度参数列表
PHP提供给我们的,可以直接使用。
- func_get_args()
- func_get_arg()
- func_num_args()
这三个函数可以使用在我们的自定义函数内部,能够返回给我们一些关于参数的信息。
function test(){
var_dump(func_get_args()); //是一个21,343,56的数组类型
}
test(21,343,56);
function test(){
var_dump(func_get_arg(0)); //获取的是int类型的21
}
test(21,343,56);
function test(){
var_dump(func_num_args()); //返回3,表示传入的参数个数
}
test(21,343,56);
21.10 创建函数
它就是用来创建函数的,通过此函数只需要定义需要的函数即可
$lang = 'eng';
if($lang=='ch')
$fn=create_function('$name','echo \'你好\'.$name;');
elseif($lang=='eng')
$fn=create_function('$name','echo \'hello\'.$name;');
$fn('李白');
21.11 判断函数是否存在
function fun(){
echo '锄禾日当午<br>';
}
if(function_exists('fun')){
fun();
}
21.12 其它
extract()
$stu=array(
'id'=>1,
'name'=>'tom'
);
extract($stu);
echo $id,'<br>',$name; //1,tom
查看一下php程序加载了哪些拓展
var_dump(get_loaded_extensions());
每个单词的首字母大写ucwords()
strnatcasecmp(不区分大小写)
<?php
//字符串比较函数
var_dump(strnatcasecmp("4","4")); //0 返回0表示两数相等
var_dump(strnatcasecmp("4","3")); //1 返回1表示第一个参数大于第二个参数
var_dump(strnatcasecmp("4","5")); //-1 返回-1表示第一个参数小于第二个参数
var_dump(strnatcasecmp("abc","ABc")); // 0
?>
22. 参数类型约束declare
如果在你的编辑器不能得到跟下图一样的结果,或许是版本太低的缘故,可以搜索菜鸟在线工具,在哪里试即可。网址https://c.runoob/compile/1
如果在函数传参的时候我只要int类型,其他类型我不要。那就再变量的前面加一个数据类型来做约束,学过强类型语言的这当然非常明白。但是呢,在PHP当中,php总是默默的将字符串2隐私转换为整数2,造成传参成功,但字符串2毕竟还是字符串,不够的严格,如下代码:
参数前没加任何约束:
参数前加了int约束:
解决字符串2也传成功的问题:
也就是说,加上declare(strict_types = 1);即可解决问题。
23. 函数返回值约束(php高版本才有,比如PHP7)
还是那句话,去菜鸟在线编辑。
格式:方法名:要约束的数据类型,如图:
24. 终止脚本执行
24.1 exit() / die()
结束当前整个程序的执行。
<?php
echo '执行到第1步了!<br/>';
exit();
echo '执行到第2步了!<br/>';
echo '执行到第3步了!<br/>';
echo '执行到第4步了!<br/>';
echo '执行到第5步了!<br/>';
?>
以上结果只输出“执行到第1步了!”,后面不再执行。
exit()函数里面可以加上字符串,比如:exit(‘对不起,程序执行结束!’)。也可以直接exit;不用加括号。
类似exit()还有die(),效果一样。
24.2 return
虽然也是终止,但它终止的是当前页面的执行。详细内容见包含文件哪章,哪里会有exit和return的区别,点击链接:跳转到包含文件章节。
25. 错误处理
25.1 错误分类
-
编译错误
编译过程中发生的错误就是编译错误。我们在编译器上写的代码如果编译器给你报错,就是编译错误。更多的是你书写错误。造成语法错误,有的编译器可能不会给你爆红,那我们看看执行结果:
编译错误,后面将不会(包括前面)执行,被中断。最常见的就是Parse error。 -
执行错误 (运行时错误)
在编译通过后,执行阶段发生的错误。此错误一旦发生,会根据错误的等级,来决定是否中断程序的执行。 -
逻辑错误
就是你的逻辑性发生的问题,程序的逻辑不严谨,而产生的错误。像这类错误我们在写代码时一定要不断的进行测试,多试几遍把多种可能结果列取出来,保证逻辑的严谨。
代码如下:<?php for($i=0;$i<5;$i--) { echo 'shixuhuan'; } //以上代码语法没有错误,也不属于执行错误,它是由于程序员的逻辑出现错误,以上for循环因为$i-- //造成死循环,是程序员的错。也就是说,由于你的代码写的不好,要完成某一个业务,别人有最优的 //算法,去解决问题,比你的性能好多了,像这种就是逻辑的一种体现,别人的解决问题方法和你的 //解决问题方法不一样,造成逻辑的不一样,出现了好代码和烂代码的差别,烂代码可能会随着时间的 //堆积,造成系统出错,网页卡顿,切换速度特别的慢等等,像这种速度慢,它不像执行错误一样会给 //你报个错,它是由人们感知的,还有体验效果的好坏,你速度慢,用户的体验效果肯定不好啦,表面 //看起来你写的代码没问题,但真正上战场的时候其实漏洞百出,这就是逻辑错误。
25.2 错误代号
所有看到的错误代号在PHP中都被定义成立系统常量(可以直接使用)
1. 系统错误
- E_PARSE():编译错误,代码不会执行。
- E_ERROR:fatal error,致命错误,会导致代码不能正确继续执行。
- E_WARNING:warning,警告错误,不会影响代码执行,但是可能得到意想不到的结果。
- E_NOTICE:通知错误,不会影响代码执行。
2. 用户错误
- E_USER_ERROR
- E_USER_WARNING
- E_USER_NOTICE
用户在使用自定义错误触发(就是后面的人为触发错误)的时候,会使用到的错误代号(系统不会用到),建议在开发环境使用。
3. 其它
- E_ALL:代表着所有的错误。(通常在使用错误控制[错误控制指的是哪些错误要展示,哪些不展示]的使用用的比较多),注意E_ALL不包含E_STRICT。
25.3 错误触发
错误触发分两种,一种是系统触发,就是系统自动给我们的错误提示。还有一种是人为触发,我们只说人为触发。如下图:
但是上面如果给用户看,它看不懂怎么办,哪就要用到人为触发,如下:
上面,如果不传第二个参数,默认是notice,notice就表示它会继续执行。第二个参数如果是error,就是E_USER_ERROR,不能写成E_ERROR,少了个user。
25.4 错误设置
-
错误显示设置:表示哪些错误该显示,以及如何显示。在PHP中,其实有两种方式来设置当前脚本的错误处理。
- PHP的配置文件:全局配置,php.ini。
打开php.ini,定位到Display_errors:是否显示错误。第二个是Error_reporting:显示什么级别的错误。
我讲一下上面的error_reporting的意思,假设是:error_reporting(~E_WARNING);
它表示除了warning,其他都显示。error_reporting(0);
表示所有错误都不显示。 - 通过脚本去设置,函数:ini_set(‘配置文件中的配置项’,配置值);如:
ini_set('error_reporting',E_ALL);
在脚本定义的配置项的优先级比配置文件高,但前题是你这段代码要运行。
- PHP的配置文件:全局配置,php.ini。
-
错误日志设置:在实际生产环境中,不会直接让错误赤裸裸的展示给用户:
- 不友好
- 不安全:错误会暴露网站很多信息(路径,文件名)
所以在生产环境中,一般不显示错误(当然,既然都上线了,那错误也比较少),但是又不可能避免会出现错误(测试的时候不会发生错误),但是又希望捕捉到可以让后台程序员看到去修改,那就需要保存到日志文件中,需要在PHP配置文件中或者代码中(ini_set)设置对应的error_log配置项。
要想让它生效前提是log_errors得开启。
25.5 自定义错误处理
最简单的错误处理:trigger_errors()函数,但是该函数不会阻止系统报错,如上图有演示。PHP系统提供了一种用户处理错误机制:用户自定义错误处理函数,然后将该函数增加到系统错误处理的句柄中,然后系统会在碰到错误之后,会使用用户定义的错误函数。
- 如何将用户自定义的函数放到系统中?set_error_handler(回调函数[用户自定义的函数],错误级别[可选])。哪我们就得写一个函数了,写这个函数,系统是有要求的。如下图:
注意:上面我着重讲一下error_reporting() & E_NOTICE
这个,首先,我们必须知道0代表false,非0代表true,我前面已经讲过了,这是个很基础的知识。好,明白了这个,我们继续看,在前面有幅图我们是打开配置文件的。是error_reporting=E_ALL & ~E_DEPRECATED & ~E_STRICT
,这啥意思,前面我也讲过了,它表示除了E_DEPRECATED和E_STRICT其他都显示,并且它已经不在E_ALL的收录范围之中了。是不是。好。error_reporting() & E_NOTICE
,把它全部展开是:E_ALL & ~E_DEPRECATED & ~E_STRICT & E_NOTICE
。这看的懂吧!那么E_NOTICE是不是包含在E_ALL的里面?是不是已经存在了?存在是不是true,它非0嘛!如果它是E_DEPRECATED ,就变成了E_ALL & ~E_DEPRECATED & ~E_STRICT & E_DEPRECATED
,前面已经说了,E_DEPRECATED 已经不在E_ALL 的收录范围之中了,所以它是false,就是0嘛!要想非0,就得把前面的~去掉。这是我的理解,如果你的理解跟我不一样,欢迎指出来哦!
然后我们来测试一下,如图:
代码copy:
<?php
function my_errors($errno,$errstr,$errfile,$errline)
{
if(!(error_reporting() & $errno)) {
return false;
}
switch ($errno){
case E_ERROR:
case E_USER_ERROR:
echo 'fatal error in file '.$errfile.' on line '.$errline.'<br/>';
echo 'error info: '.$errstr;
break;
case E_WARNING:
case E_USER_WARNING:
echo 'Warning in file '.$errfile.' on line '.$errline.'<br/>';
echo 'error info: '.$errstr;
break;
case E_NOTICE:
case E_USER_NOTICE:
echo 'Notice in file '.$errfile.' on line '.$errline.'<br/>';
echo 'error info: '.$errstr;
break;
}
return true;
}
echo $a;
set_error_handler('my_errors');
echo '<hr>';
echo $a;
26. 正则表达式
26.1 何为正则
正则表达式它就是描述了一类字符串的特征,通过这个特征可以与特定的函数配合使用,对其它的字符串进行匹配啊,查找啊,替换啊,分割啊,等等其它操作。不是所有的字符操作都用正则表达式的,只有当我们遇到复杂字符串的时候,才会用到正则表达式。在数据类型字符串那章,已经讲过字符串处理函数。其实它可以解决一些简单的字符串问题。只有复杂字符串处理才会用到正则。
说白了,就是来描述一个字符串,从而来匹配找到符合特征的一类字符串。类似于通过描述凶手的特征,从而来找到犯人。
26.2 语法规则
正则表达式是一个特殊的字符串,这类字符串的特征是由一个或多个:
1) 普通字符(比如a到z),A-Z,0-9,双引号,单引号,
2) 元字符(有特殊功能的字符比如*,+,?, \d,\s 等等),
等组成的一个字符串。
例如: ‘/a/’ , a就是普通字符,/是定界符(表示正则表达式的开始或结束)
定界符
我们一般习惯用正斜线 "/"作为定界符。当然除了字母,数字,和正斜线以外的字符都可以作为定界符,比如#, !, {}, |, 都是可以的!注意,定界符放在正则表达式的起始位置,前后要一致。
26.3 与正则表达式匹配的函数(1)
1) preg_match_all
按指定的正则表达式,在给定的字符串中进行搜索,匹配到符合特征的部分取出来。
<?php
$pattern = '/test/';
$str='abc';
var_dump(preg_match_all($pattern,$str,$arr)); //第一个是正则表达式,第二个是被搜索的字符串,第三个是数组 结果是int 0,表示没找到匹配的。
//解读:在$str中搜索,看看有没有符合/test/这个特征的,如果有,取出来,放数组中
$pattern1 = '/test/';
$str1='abctestnihaoya';
var_dump(preg_match_all($pattern1,$str1,$arr1));
//结果是int 1,1就说明找到了,找到了1个,1个符合特征,仔细看$str1。
//如果 $str1是abctestnihaoyatest'; 结果就是int 2,有2个符合特征。
var_dump($arr1); // 通过数组输出来。
正则表达式里面是可以用转义字符的,比如转义一个单引号。
26.4 与元字符搭配
匹配一个字符:
-
\d
:匹配任意一个十进制数字,等价于[0-9]==<?php $pattern='/t\dst/'; //解读:\d,上面已经解释了,所以上面t\dst匹配到的应该是t0st~t9st,注意是1个,比如01,这就变成两个字了,不行。 //很显然,下面的$str并没有与之匹配,所以数组为空。 $str='abctests'; var_dump(preg_match_all($pattern,$str,$arr)); var_dump($arr);
-
\D
:匹配任意一个除十进制数字以外的字符,等价于[^0-9]
与上面的例子是相反的,就是除了0~9的不匹配,上面的不是匹配t0st,t1st,t2st,t3st…t9st吗,我跟它相反就是了,匹配0~9之外的字符。 -
\s
:匹配任意一个空白字符,比如换页符,换行符(\n,注意\n要用双引号括起来,看前面的单引号和双引号的区别有说),回车符(\r),制表符(\t),垂直制表符
-
\S
:匹配除空白字符以外的任何一个字符,与\s相反就对了。 -
\w
:匹配任意一个数字或字母或下划线。 -
\W
:匹配除数字,字母,下划线以外的任意一个字符。 -
.(一个点)
:匹配除换行符(\n)以外的任意一个字符。
匹配多个字符:
-
*
:匹配0次,或1次,或多次其前面的字符。也就是说,放在*前面的字符可以出现0次,2次,或多次。<?php $pattern='/te*st/'; //说明*前面的e即可以出现0次,1次或多次 $str1='abctests'; //这里e出现1次,匹配上,不出现e也可以。 var_dump(preg_match_all($pattern,$str1,$arr1)); var_dump($arr1);
-
+
:匹配1次,或多次其前面的字符。也就是说前面的字符至少出现一次。不能不出现。 -
?
:匹配0次,或1次其前面的字符。 -
{n}
:表示其前面字符恰好只能出现n次。 -
{n,}
:表示其前面字符出现不少于n次,就是大于等于n次。 -
{n,m}
:表示其前面字符至少出现n次,最多出现m次。 -
|
:匹配两个或多个模式
上图表示了它即可以匹配test,也可以匹配abc。 -
[]
:匹配方括号中的任意一个字符。
上图表示即可以匹配e,也可以匹配a,也可以匹配b,所以,凡是出现test,tast,tbst都是可以匹配到的。 -
[^]
:匹配除方括号中字符以外的任意一个字符,注意跟上面那个^以什么什么开始是没有关系的,此处是跟[]
取反。比如: "/t[^e]st/"就表示凡是出现test的字符串是不能匹配的,除了e,其它都可以。
开始结束:
-
^或\A
: 匹配字符串开始位置。<?php $pattern='/^test/'; $str='abcdefgtesthaha'; var_dump(preg_match_all($pattern,$str,$arr)); var_dump($arr);
结果是一个也匹配不是,因为它只匹配以t开头的字符串,而上面是以a开头,所以匹配不上。
-
$或\Z
: 匹配字符串的结束位置,跟上面相反,不做解释。
把前面的理解了,把它们混合使用也是种很简单的是。比如’/t.{3}st/’,点跟{}混合使用。类似/t…st/,其实道理都是一样的,我不做过多解释。
圆括号:
- ():将括号中作为一个整体以便将其中的内容获取到,在我们的正则表达式中,可以使用圆括号来将某一段括起来(像点啊,*啊都可以),在圆括号的后面部分,我们可以使用\\数字 来代表圆括号部分所匹配到的内容。不明白,没关系,认真看下面的图,图中还有解释,就明白了。
可以看出它把es也放到数组中。
26.5 贪婪匹配
<?php
$pattern='/t.*t/';
$str='abctsyztchtyout';
var_dump(preg_match_all($pattern,$str,$arr));
var_dump($arr);
上面的代码中,它是会输出tsyzt还是tsyztchtyout?这个是不是就不知道了,里面有三个t,那么它是从第二个t就结束,还是到最后的t才结束,这就是我要说的贪婪匹配。
答案很明显,它是到最后一个t才结束匹配的。如果你后面还有t,它还好向后继续匹配。是不是比较贪婪呢?所以默认情况是贪婪匹配。那我不需要贪婪匹配怎么解决?
没错,在.*后面加上?号就可以结束贪婪匹配。上面是不是匹配到了两个,一个是tsyzt和tyout,就是把所有匹配的都匹配出来。
26.6 模式修正符
模式修正符也是符号,它是在正则表达式的定界符之后使用的,可以调整正则表达式的解释,扩展正则表达式在匹配,替换等操作时的某些功能,增强正则表达式的处理能力。
-
i:在和模式进行匹配时不区分大小写
<?php $pattern='/test/'; $str=' test TEST Test TeSt'; var_dump(preg_match_all($pattern,$str,$arr)); var_dump($arr); //结果是只要一个匹配test,也就是说,匹配是严格区分大小写的。
想让所有匹配上,一个字母就搞定!
<?php $pattern='/test/i'; $str=' test TEST Test TeSt'; var_dump(preg_match_all($pattern,$str,$arr)); var_dump($arr); //最终输出结果:int(4) array(1) { [0]=> array(4) { [0]=> string(4) "test" [1]=> string(4) "TEST" [2]=> string(4) "Test" [3]=> string(4) "TeSt" } }
-
m:多行匹配,如果目标字符串中没有"\n"字符,或者模式中没有出现^或$,设置这个修饰符不产生任何影响。
使用条件:1.目标字符串必须包含"\n",在字符串中出现换行符表示新的一行开始。2.正则表达式中必须要出现^或者$符。这两个条件缺一不可。<?php $pattern='/^test/'; $str="test\ntest\ntest\ntest"; //必须使用双引号 var_dump(preg_match_all($pattern,$str,$arr)); var_dump($arr); //结果是数组里只有一个test
<?php $pattern='/^test/m'; //当我使用模式修正符m $str="test\ntest\ntest\ntest"; //必须使用双引号, var_dump(preg_match_all($pattern,$str,$arr)); var_dump($arr); //最终结果是:int(4) array(1) { [0]=> array(4) { [0]=> string(4) "test" [1]=> string(4) "test" [2]=> string(4) "test" [3]=> string(4) "test" } } 上面的$str相当于://加了m就表示每一行的开头都可以匹配 $str="test test test test "
当然,如果你不是win10的,你按上面这样敲回车是不行的。因为在windows操作系统中你所看到的换行其实是通过两个字符完成的(\r\n),在linux操作系统中看到的换行,就是通过\n来完成的。 -
s:如果设定了此修正符,那么.(点)将匹配所有的字符包括换行符(\n)。在上面我们的点是匹配除换行符以外的字符,现在不同。我们通过一个模式修正符s就搞定。
-
U:禁止贪婪匹配,在前面的方案中我们是用?号来禁止贪婪匹配的,现在我们一个修正符U也可以匹配。
最终,说明一点,模式修正符是可以搭配使用的。
26.7 与正则表达式匹配的函数(2)
-
preg_match
执行一个正则表达式匹配,它不像preg_match_all,一个是all(全部的意思),一个没有all,所以preg_match_all是整个变量遍历查询,去掉all只遍历一个。第一次匹配到将停止搜索。它返回的要么是0,要么是1。所以我们可以拿它做判断条件。<?php $pattern='/test/'; $str="hellotestwoqutest"; var_dump(preg_match($pattern,$str,$arr)); //搜索到一个test,不会再往后搜索了。 echo "<br>"; if(preg_match($pattern,$str,$arr)) { echo '找到了<br>'; var_dump($arr);//输出结果是array(1) { [0]=> string(4) "test" } }else{ echo '没找到'; } //它还有第四个参数,第四个参数表示匹配到的test在整个字符串的位置, //如我们在if判断的条件里的那个函数加上第四个参数 //preg_match($pattern,$str,$arr,PREG_OFFSET_CAPTURE) //输出的结果$arr是:array(1) { [0]=> array(2) { [0]=> string(4) "test" [1]=> int(5)} },看看索引为1的,[1]=> int(5),为5,再数数,是不是在字符串索引为5的位置。
-
preg_replace
执行一个正则表达式的搜索和替换。它有三个参数,第一个参数:正则表达式,第二个参数:要替换成的字符串。第三个参数:目标字符串。
下面的代码是要把div替换成a标签。<?php $pattern='/<div>xiaomei<\/div>/'; //小美 $str1='<a href="#">xiaoming</a>'; //小明 $str="<div>xiaomei</div>nihaoya"; //把小美你好呀改成小明你好呀,并且从div变成a标签 if(preg_match($pattern,$str,$arr)) { var_dump(preg_replace($pattern,$str1,$str));//这里是不是把小美你好呀改成小明你好呀了吗? }else{ echo '没找到'; }
最终结果如下所示:
问题又来了,如果我只是单纯的想把div变成a标签,不改变里面的内容,又该怎么做呢?
答:其实上面我们已经做过了,往上看,就是圆括号哪一节,我们可以把$pattern里的xiaomei打上圆括号,然后想表达它,是不是用\\1去表示它呢?同理,把它放在$str1也是可以的,如下代码,你更能理解我这句话:
当然了,\\1也可以写成$1,\\2就是$2,以此类推哦。
它还有第四个参数(可选),默认是-1,代表替换所有符合特征部分的,0代表不替换,1代表只替换前面符合特征的那一个,往后就即使符合特征也不替换,只替换1个,就这意思。
它还有第五个参数(可选),表示替换的次数,用一个变量来表示$count。
-
数组的一一对应
<?php
$pattern=array(
'/<div>(xiaomei)<\/div>/',
'/<p(.*?)>(.*?)<\/p>/',
);
$str1=array(
'<a href="#">$1</a>',
'<span$1>俺其实是span标签啦!!!($2)</span>',
);
$str="<div>xiaomei</div>nihaoya,<p style='color:red'>俺是p标签啦!!</p>";
echo '替换后的字符串:'.preg_replace($pattern,$str1,$str);
echo '<br><br><br>';
echo '原来的字符串:'.$str;
详细见下图。
注意:用数组就不要去if判断了。
27. 日期与时间
我们可以通过相关的函数来获取服务器的时间和日期,在开发中我们或多或少肯定会用到时间函数,比如记录文章发布时间等等。
27.1 设置时区(解决时间差)
不同的国家所处的时区是不一样的,而不同的时区也会有时间差,所以在不同的时区获取到的时间是不一样的,比如我们中国现在是白天,但美国可能就是黑夜了。可以简单理解为,你在不同的国家,看到的时间是不一样的,会有时间差。默认时区是UTC(像我们国家就是PRC),我们所处的国家是中国,所以我们要设置成我们国家的时区。
//第一种方法
date_default_timezone_set('Asia/Shanghai');
//第二种方法
//打开php.ini,搜索date,找到date.timezone,给他赋值为PRC,然后重启。
27.2 当前Unix时间戳
从Unix纪元(格林威治时间1970年1有1日00时00分00秒)开始到当前的秒数。就是时间戳,time()函数。
<?php
date_default_timezone_set('Asia/Shanghai');
var_dump(time());
27.3 指定时间的Unix时间戳
mktime()。它里面的参数是mktime(小时,分,秒,月,日,年)。和strtotime
<?php
date_default_timezone_set('Asia/Shanghai'); // 这个不能省
//算出我现在的时间距离2021年1月1日0点0分0秒还有多少秒。
$nowtime = time();
//计算时间戳的第一种方法:
$time1 = mktime(0,0,0,1,1,2021); //2021年1月1日的时间戳
echo '距离2021年1月1号还有'.($time1-$nowtime).'秒';
//距离2021年1月1号还有6166024秒
//1分钟 = 60秒;
//所以($time1-$nowtime)/60 = χ分钟
//1小时 = 60分钟;
//所以($time1-$nowtime)/60/60 = χ小时
//1天 = 24小时;
//所以($time1-$nowtime)/60/60/24 = χ天
//计算时间戳的第二种方法:
$time2 = strtotime("2021-01-01 00:00:00");
echo $time2;
<?php
date_default_timezone_set('Asia/Shanghai');
$currenthour = date('H');
print('2个小时后为:');
print(date('Y-m-d H:i:s',mktime($currenthour+2)));
27.4 从Unix时间戳取得时间日期信息
根据时间戳我们根本不知道是几年几月几秒,所以我们需要一个函数,date(),直接看代码。
<?php
date_default_timezone_set('Asia/Shanghai');
// date()格式化一个本地时间/日期
// date(时间日期格式,时间戳); //不传时间戳,就是当前时间戳
var_dump(date('Y')); //string(4) "2020",Y就被转化为2020了,小y是2位年号,比如1999用小y就是99。
var_dump(date('Y-m-d')); // string(10) "2020-10-22"
var_dump(date('Y-m-d G:i:s')); // string(18) "2020-10-22 9:41:33"
// -和: 都是原样输出的。
var_dump(date('Y-n-d G:i:s'));
// n跟m的区别是:比如九月份,m是09。n是9,没有前面那个0。
// 其他的可以查手册。
27.5 获取Unix时间戳和微秒数
microtime() 返回当前Unix时间戳和微秒数,可用于文件上传。
<?php
date_default_timezone_set('Asia/Shanghai');
var_dump(microtime()); //string(21) "0.68819700 1603331482" 前面的是微秒数,后面的是秒数
// 我不想以上的格式怎么办,就需要用到第一个参数,它是布尔值,我们写个true
var_dump(microtime(true)); // float(1603331622.8472) 小数点前面是秒数,后面是微秒数
//我们可以用它来记录for循环执行的时间
$startTime = microtime(true);
for($i=0;$i<100000;$i++){
}
$endTime = microtime(true);
echo '该for循环花费了'.round(($endTime-$startTime),4).'秒';
//该for循环花费了0.0091秒,上面的round()函数的第二个参数表示保留小数点后几位。
27.6 检查日期是否合法
用checkdate(月,日,年)
<?php
date_default_timezone_set('Asia/Shanghai');
if(checkdate(10,32,2020)){
echo '日期合法';
}else{
echo '日期不合法'; //因为压根就没有10月32好这一天,所以不合法。
}
28. 文件与目录操作
28.1 判断普通文件和目录(文件夹)
1) is_file(): 判断给定文件名是否为一个正常的文件
2) is_dir(): 判断给定文件名是否为一个目录
<?php
var_dump(is_file('C:\Users\chting\Desktop\phptest\test1\index.php')); //返回bool(true)
28.2 文件的属性
1) file_exists(): 判断文件是否存在。
2) filesize(): 取得普通文件的大小,单位是字节。要kb,直接查公式换算即可,像上面讲时分秒是一样的,此处不累赘。
3) is_readable(): 判断给定文件名是否可读。
4) is_writable(): 判断给定文件名是否可写。
5) filectime(): 获取文件的创建时间,返回时间戳,用前面讲的date函数格式化即可。
6) filemtime(): 获取文件的修改时间。
7) fileatime(): 获取文件的上次访问时间。
8) stat(): 给出文件的信息。【了解即可】
28.3 目录的基本操作
1) basename(): 返回路径中的文件名(比如index.php)部分。
2) dirname(): 返回路径中的目录(文件名给去掉了) 部分。
3) pathinfo(): 返回文件路径的信息。
4) opendir(‘文件路径’):返回的是资源类型: 打开目录句柄(理解就是哪个资源)。
5) readdir(资源):从目录句柄中读取条目,返回目录中下一个文件的文件名。
6) rewinddir(资源):倒回目录句柄。
7) closedir(资源):关闭目录句柄。
8) mkdir(目录名,目录的权限):新建目录。目录权限默认是0777,表示可读可写。 目录权限可以不写。第三个参数如果是true,表示可以一层层的创建,比如我们创建a目录,a目录里面又有b目录,b目录里面又有c目录,使用true,就可以把a,b,c目录三个文件夹一并创建啦,文件路径就是xxx/a/b/c。
9) rmdir(空目录):删除指定的空目录。
10) scandir(目录名):列出指定路径中的文件和目录。
28.4 文件的基本操作
1.fopen(文件路径,打开方式):打开文件或URL ,返回的是资源类型,第二个参数有下面几种:
- r: 以只读方式打开,将文件指针指向文件头。
- r+: 以读写方式打开,将文件指针指向文件头。
- a: 写入方式打开,将文件指针指向文件末尾,如果文件不存在则尝试创建。
- a+: 读写方式打开,将文件指针指向文件末尾,如果文件不存在则尝试创建。
2.fread(资源句柄,读取的长度或字节数):读取文件,返回string。
<?php
//新建一个b.txt,里面的内容是abcdefg
$file = fopen('C:\Users\chting\Desktop\phptest\test2\b.txt','r');
var_dump(fread($file,1)); //读取一个字节,所以读到的是a
var_dump(fread($file,1)); //再读取一个字节,所以读到的是b
//如果不是英文,而是中文,那么就不是占1个字节了,而是3个字节。前提还要看看你有没有设置UTF-8编码。
3.fgets(资源句柄):读取一行。再读,又是一行。
4.feof(资源句柄):测试文件指针是否到了文件结束的位置。我们用fgets去一行行的读取,哪有没有到最后面呢,也就是有没有读到最后一行,我们就可以用feof去测试它,false表示没有到最后面,也就是后面还有内容。
5.fwrite(资源句柄,‘内容’):写数据。
<?php
$file = fopen('C:\Users\chting\Desktop\phptest\test2\b.txt','r+');
var_dump(fwrite($file,'美')); //返回的数字3表示它写入了几个字节。
//打开文件发现,第一个字被覆盖掉了。
6.fseek(资源句柄,偏移量,设定文件尾):在文件指针中定位,我们可以看下面代码。
如果我们不想在最前面开始写,我们就可以定一下指针的位置。
<?php
$file = fopen('C:\Users\chting\Desktop\phptest\test2\b.txt','r+');
fseek($file,0,SEEK_END); //第二个参数0表示一个都不移动,第三个参数表示在末尾,就是在文件的末尾一个都不移动。效果就是在文件末尾添加你写的数据,其实就是追加内容。不会覆盖哦。
var_dump(fwrite($file,'美'));
注意:在末尾追加内容我们并不会用fseek,那么麻烦,还要定位,我们把fopen的第二个参数改为a+就行了。所以fseek了解即可。看下面代码:
$file = fopen('C:\Users\chting\Desktop\phptest\test2\b.txt','a+');
var_dump(fwrite($file,'美'));
7.rewind(‘资源句柄’):倒回文件指针位置。就是你读内容读到一半,用到这个函数,又得重新读。跟上面的倒回目录句柄其实意思是一样的。
8.flock(‘资源句柄’):给文件加锁。就是我在写不允许别人也在写,只有我写完,你再写,依次排队。所以这个函数会造成文件阻塞。
$file = fopen('C:\Users\chting\Desktop\phptest\test2\b.txt','a+');
IF(flock($file,LOCK_EX)){ //第二个参数表示独占锁(我写的时候其他人不允许打扰),还有其他锁,比如其中一个解锁。还有一个共享锁LOCK_SH,这是用于读取的时候用的。
var_dump(fwrite($file,'美'));
flock($file,LOCK_UN); //释放锁。
}else{
echo '文件加锁失败';
}
如果我要写的文件被别人用独占锁独占了,那我就被堵塞了,一直等他写完我再写,如果我不希望堵塞,就可以用另一个锁,多个锁用加号连起来,比如:
$file = fopen('C:\Users\chting\Desktop\phptest\test2\b.txt','a+');
IF(flock($file,LOCK_EX+LOCK_NB)){ //不希望在加锁的时候发生堵塞,锁被他人占用,直接跳到else里。
var_dump(fwrite($file,'美'));
flock($file,LOCK_UN);
}else{
echo '文件加锁失败';
}
9.fclose(‘资源句柄’):关闭一个已打开的文件指针。
10.copy(‘资源句柄’):拷贝文件。
11.unlink(‘资源句柄’):删除文件。
12.file_get_contents(文件路径):读取文件内容。返回一个字符串。也可以打开一个网络地址。
13.file_put_contents(文件路径,要写的内容):将字符串写入文件中,会覆盖原来的内容,所以慎用。
<?php
header('content-type:text/html;charset=utf-8');
file_put_contents('test.txt',file_get_contents('http://baidu')); //相当于查看源码
14.rename():重命名一个文件或目录。
15.readfile():读入一个文件并写入到输出缓冲,用于下载文件比较多。
29. 文件上传
1. html页面设置,新建一个php文件,再把以下代码copy上去
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>文件上传</title>
</head>
<body>
<!-- 要做文件上传,form表单所需要设置的属性
method设置为post
enctype设置为multipart/form-data
可选:form表单中设置隐藏类型的input,其中name值设置为MAX_FILE_SIZE,VALUE值设置为需要限制的上传文件的大小(单位是字节)
-->
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="myfile" />
<input type="submit" name="submit" value="开始上传">
</form>
</body>
</html>
2. 与上传有关php服务器配置(打开php.ini)
配置项 | 可能值 | 功能描述 |
---|---|---|
file_uploads | ON | 确定服务器上的PHP脚本是否可以接收HTTP文件上传,on代表开启,否则不能通过http上传文件 |
memory_limit | 128M | 设置脚本可以分配的最大内存量,防止失控的脚本独占服务器内存 |
upload_max_filesize | 2M | 限制PHP处理上传文件的最大值,此值必须小于post_max_size值 |
post_max_size | 8M | 限制通过POST方法可以接收的信息最大量 |
upload_tmp_dir | c:/wamp/tmp | 上传文件存放的临时路径,可以是一个绝对路径。 |
如果我们要上传比较大的文件,可能会去改上面的某些配置。
3. $_FILES多维数组,用于存储各种与上传有关的信息,我们可以上传一个文件,如下图:
上传后的结果:
注意:上传后产生的临时文件php832C.tmp这个文件随着脚本执行结束会被清除掉。这个问题怎么解决呢?请看第4点:PHP文件处理函数。
解读:$FILES[‘file’][‘name’]: 文件名,包括扩展名
$FILES[‘file’][‘size’]: 已上传文件的大小,单位是字节
$FILES[‘file’][‘tmp_name’]: 文件上传后,在服务器端存储的临时文件名
$FILES[‘file’][‘error’]: 文件上传时产生的错误,0代表没有错误,文件上传成功。1代表上传文件的大小超出了在PHP配置文件中upload_max_filesize选项限制的值。2代表上传文件大小超出了HTML表单中MAX_FILE_SIZE选项所指定的值,如果为3代表文件只有部分上传。4表示没有上传任何文件。
$FILES[‘file’][‘type’]:获取客户端上传文件的MIME类型,MIME类型规定了各种文件格式的类型,每种MIME类型都是由 / 分隔的主类型和子类型组成,主类型写在前面,后面才是子类型。
4. PHP文件处理函数:用于上传文件的后续处理
is_uploaded_file()
判断指定的文件是否通过HTTP POST上传的。可以保证安全。
move_uploaded_file()
文件上传后,首先会存储于服务器的临时目录中,可以使用该函数将上传的文件移动到新位置。它有两个参数,第一个参数是临时文件,第二个参数是新的位置。返回的是boolean类型(用于判断是否上传成功)。请仔细看下图,别遗漏注释上的内容:
首先我会在桌面上新建一个名字叫a的文件夹,然后把上传的文件存放到桌面上的a文件夹里:
然后我打开桌面上的a文件夹,发现里面刚好有个名叫nihao.txt文件,打开看,果然里面有abcdefg这几个内容,说明上传成功。并且不会丢失。
注意点:
如果我上面的move_uploaded_file()函数的第二个参数,没写扩展名,txt,那么我上传的haha.txt的时候,它会不会自动把txt该补上呢?答案是不会的,哪怎么办呢?这就需要用到一个函数了,叫pathinfo(),这个函数我们其实前面就已经学过了,这里我就不放图了,还有一个问题,我上面第二个参数的文件名写了个a,是不是写死了,我往后再提交一个文件就会把之前的覆盖掉,所以文件名是不能重复的。我们也不能说上传之前叫haha,上传之后还叫haha,万一有两个用户都起了一样的文件名叫haha,你上传之后还叫haha,哪不也覆盖掉了吗?所以文件名我们得必须采用随机数的方式去弄。
代码copy:
<?php
header('Content-type:text/html;charset=utf-8');
if(isset($_POST['submit'])){
if(is_uploaded_file($_FILES['myfile']['tmp_name'])){
$arr = pathinfo($_FILES['myfile']['name']);
$kuozhanming = $arr['extension'];
$newName = date('YmdGis').rand(1000,9999);//用随机数做文件名,防止重复
if(move_uploaded_file($_FILES['myfile']['tmp_name'], "C:\\Users\\33048\\Desktop\\a\\{$newName}.{$kuozhanming}")){
echo '恭喜你,上传成功!!';
}else{
echo '上传失败!!';
}
}else{
exit('可能有攻击!!');
}
var_dump($_FILES);
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>文件上传</title>
</head>
<body>
<!-- 要做文件上传,form表单所需要设置的属性
method设置为post
enctype设置为multipart/form-data
可选:form表单中设置隐藏类型的input,其中name值设置为MAX_FILE_SIZE,VALUE值设置为需要限制的上传文件的大小(单位是字节)
-->
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="myfile" />
<input type="submit" name="submit" value="开始上传">
</form>
</body>
</html>
30. 文件下载
其实当我们用浏览器打开一个资源,比如html页面,是可以打开的,但是有一些资源,浏览器是打不开的,它就会让你保存到本地,比如:localhost/demo/a.rar,这就是文件下载,但是这样a.rar就暴露在地址栏上了,不好,所以现在我们用php代码来模拟一下。
//文件的下载
$file='a.rar'; //换成你的压缩文件的路径
// 1. 发送指定的文件MIME类型的头信息:header('Content-type:MIME类型');
// 获取文件的MIME类型:需要用到一个函数Fileinfo,不过这个函数是要安装一些扩展的,所以我们要先安装好,再使用,这个函数是php的扩展函数。
$fileinfo = finfo_open(FILEINFO_MIME_TYPE); // 返回的是资源
// var_dump(finfo_file($fileinfo,$file)); //第二个参数是压缩文件的路径,就这里要变,改成你的路径即可,其他都是死的。它返回的是"application/x-rar";
$mimeType = finfo_file($fileinfo,$file);
//我们之前写过编码的,text/html,就是告诉浏览器最终用html方式打开,哪我们获取压缩文件的mime类型也是一样的道理,最终以application/x-rar方式打开。
finfo_close($fileinfo); //释放资源
header("Content-type:".$mimeType); //函数向客户端发送原始的HTTP报头(发送一个自定义的http报文) 模拟一个压缩文件xxx.rar
//这就相当于告诉浏览器我要返回一个像$mimeType这样的一个类型的文件。
// 2. 指定下载的文件的描述
//header('Content-Disposition:attachement;filename=文件名称');
header('Content-Disposition:attachement;filename='.basename($file));
// 3. 指定文件的大小
// header('Content-Length:文件大小'); //单位是字节,取得文件的大小是filesize函数
header('Content-Length'.filesize());
// 输出文件到浏览器,用readfile函数
readfile($file);//其实这一步就:http://localhost/demo/index.php相当于localhost/demo/a.rar
下面是排除了上面注释的部分,可以copy:
<?php
if(!function_exists('finfo_open')){
header('content-type:text/html;charset=utf-8');
exit('请先开启PHP扩展:fileinfo');
}
$file='a.rar';
$fileinfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($fileinfo,$file);
finfo_close($fileinfo);
header("Content-type:".$mimeType) ;
header('Content-Disposition:attachement;filename='.basename($file));
header('Content-Length:'.filesize());
readfile($file);
31. 包含文件
如果多个页面都需要用到相同的头(banner),尾(版权),说白了,就是要用到相同的代码。我们可以将相同的页面做成包含文件,在展示的页面中包含进去即可,可以被包含多次。
包含文件相当于将文件的内容复制到页面中,所以注意包含文件里面不包含文件的基本结构(<html></html>),包含后,页面中就不止一个页面结构了。
31.1 路径问题
1. 相对路径:以自身的所在的目录为参照。
2. 绝对路径:以盘符或者站点根目录为参照。
相对路径比较简洁,但是可能由于页面之间多次相互包含,地址也因此出现问题。这个时候,建议使用绝对路径。
31.2 require() 和 include()
新建一个index.html页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div style="width: 100px;height: 100px;background-color: red"></div>
</body>
</html>
再新建一个php页面
<?php
//php也可以引入,它只是拷贝里面的内容,不考虑你是html或者php。
require 'index.html';
include 'index.html';
?>
31.3 require() 和 include()两者区别
1.相同点:可以包含多次 。
2.不同点:如下图:
require遇到错误停止执行,include遇到错误继续执行。
31.4 include_once() 和 require_once()
解读:只能包含一次。
带once和不带once的效率比较
很显然,论效率,肯定不带once的效率高,因为带once在包含之前要判断一下此文件是否被包含,如果包含了,就不再包含,没包含,哪就包含,因为它只包含一次,所以带once的效率较低。
31.5 注意点
1. 魔术常量如__FILE__和__LINE__与包含和不包含是没有关系的,如下代码:
//这是index.php
<?php
echo __FILE__,'<br>';
echo __LINE__,'<br>';
//这是a.php
<?php
include 'index.php';
?>
执行a.php文件,最终结果如下:
C:\Users\chenting\Desktop\phptest\test2\index.php
3
我们发现魔术常量只针对本页面,第一个答案它并不是a.php,而是index.php。魔术常量是所在文件的信息,即使a.php拷贝index.php的代码。
2. exit 和 return
exit()终止所有页面,return终止当前页面。
3. return的作用:
1. 终止函数执行
2. 从函数中返回值
3. 终止当前脚本执行
4. 用来做配置文件,如下图:
31.6 ./目录/文件 和 目录/文件 的区别
./表示当前目录,所以一般它们是没有区别的,但也有例外。
不带点的受到include_path的影响,我们可以通过以下代码查看include_path。
<?php
phpinfo();
然后执行,就会出现如下图:
CTRL+F: 找到include_path:
解读:也就是说,不带点的,它会先去当前目录里去找,找不到,再去D盘下D:\DevelopSoftware\xampp\php\PEAR这个目录下去找。我们可以在php.ini定位到include_path,去修改它的值。比如我们可以把它从D盘变为C盘。反正不带点的除了在当前目录找,还会去你指定的目录找。而带点的就只能在当前目录找,因为它被限定了。
我们除了可以在配置文件中,修改include_path,也可以在PHP代码中修改,比如:set_include_path()。设置包含文件的目录。
set_include_path()有什么用呢?
安全性。因为我们可以修改它的包含文件的目录位置。这样让它不在站点下,在站点外,通过http是无法访问的,比如涉及到数据库连接的用户名和密码。这样我放到站点下,通过http就无法访问到了,这就是它的安全性。
32. namespace隔离函数
PHP 命名空间(namespace)是在PHP 5.3中加入的。
新建一个a.php:
<?php
function make(){
echo 'aaa';
}
?>
新建一个b.php:
<?php
function make(){
echo 'bbb';
}
?>
这时候你发现了a.php和b.php里面有同名方法,现在我们再新建一个1.php文件。
<?php
include 'a.php';
include 'b.php';
?>
在1.php文件中引入a.php,和b.php它会报错,因为你引入了同名函数,哪这个问题怎么解决呢?这就要用到namespace了,它相当于一个文件夹,就像在外面包了一层,我们知道,在一个文件夹的同级下面,是不允许出现两个名字一样的文件的,但是如果你放在不同的文件夹,名字是可以一样的。那么namespace也是一样的道理。我们给a.php搞一个namespace,给b.php也搞一个namespace。如下代码:
改造后的a.php:
<?php
namespace AAA; //名字随便起,可以理解这在AAA的文件夹下
function make(){
echo 'aaa';
}
?>
改造后的b.php:
<?php
namespace BBB; //可以理解这在BBB的文件夹下
function make(){
echo 'bbb';
}
?>
改造后的1.php:
<?php
include 'a.php';
include "b.php";
AAA\make(); //调用AAA下的make方法
echo '<br>';
BBB\make(); //调用BBB下的make方法
这样就不会出现方法名冲突啦!!最终结果就是:
aaa
bbb
说到namespace,这里我就不得不提到一个魔术常量了,它就是__NAMESPACE__
。它可以打印你当前脚本所在的命名空间名。
33. 会话管理
说简单点,当我们去访问一个网站的页面以后,再去访问同一个网站的另外一个页面时,服务器并不知道两次访问同一个网站的是一个人,就像我们第一次去登陆这个网站,然后我们把计算机关了,到第二天在去登这个网站发现直接就进了,不需要登陆,它自动的就知道我的身份,像这种技术就需要用到今天讲的会话管理,详细的我可以再出一个笔记来讲讲会话。没有基础的,可以先自行百度一下。怎么解决?主要有两种cookie和session。
cookie
Cookie是用来将网站的资料记录在客户端的技术,这种技术让web服务器能将一些资料,存放于客户端(用户的电脑)之中。
你可以理解为服务器是一个健忘的人,你来过一次下一次再来它是不会认的你的,他会以为你是第一次来,就要你再重新登记一下信息,是不是很麻烦。那为了解决服务器这个健忘的毛病,在服务器端当你登记完信息的时候,它会把信息再复制一份比如纸条给你保留着,下一次来就把它带上,给服务器端的人看,这样,你就不需要再次去登记信息啦!
上面由 我们(浏览器) 保管的纸条就是cookie。cookie是保存在浏览器端的。
新建一个index.php
<?php
header('Content-type:text/html;charset=utf-8');
// 1.向客户端电脑中设置Cookie,浏览器接收到就会存在浏览器的cookie里。
var_dump(setcookie('name','xiaochen',time()+3600)); //第三个参数是有效期,就是你的这个纸条的有效期,过了就不起作用了。name是属性,xiaochen是值。true表示设置成功。
新建一个1.php
我们在index.php中已经设置了cookie的信息给浏览器保存,浏览器再次访问,就要带上它的纸条(cookie),比如它现在要访问1.php,那么在1.php我们就要获取它的cookie信息,看看它是谁,不然,我不知道它曾经访问过index.php,就用得给它设置cookie,麻烦,所以,在1.php中我们就要来获取它从客户端发送过来的cookie信息,哪怎么获取呢?这就需要用到一个超全局变量$_COOKIE。它会负责接收cookie信息,它是一个数组,我们前面讲超全局变量已经讲过了。
<?php
header('Content-type:text/html;charset=utf-8');
var_dump($_COOKIE);
效果如下:
注意:如果上图的格式看的不好,可以右击打开网页源代码查看,格式就好多了,但是不用这么费劲,直接在php的页面写上echo '<pre>'
;一句话即可。
很明显,在1.php是不是就把xiaochen给获取到了呀!!再建一个页面也是一样的效果。
二维数组
在index.php除了设置一个name,我还设置一个email。
<?php
header('Content-type:text/html;charset=utf-8');
var_dump(setcookie('name','xiaochen',time()+3600));
var_dump(setcookie('email','xxxxxxxxx@qq',time()+3600));
打开1.php,查看效果:
我们发现,name和email都是放在$_COOKIE这个大数组里面的,现在我们想把name和email,因为是同一个人的,我想放在另一个数组中,其实就是二维数组,数组里再嵌套数组这种形式,怎么实现呢?
很容易,我们打开index.php,对它进行编辑。如下代码:
<?php
header('Content-type:text/html;charset=utf-8');
var_dump(setcookie('member[name]','xiaochen',time()+3600));
var_dump(setcookie('member[email]','xxxxxxxxx@qq',time()+3600));
再次打开1.php进行测试,效果如下:
删除cookie:
我们可以再建一个3.php页面。
setcookie("name","",time()-1); //主要还是第三个参数,把时间设为过去,就是过期了。
//把原来的name过期掉。想多维数组的要一个一个删,比如上面的member,是这样删的,比如setcookie("member[name]","",time()-3600);但是一个一个删比较麻烦,我们可以按foreach遍历来删,如下:
遍历二维数组:
<?php
foreach($_COOKIE['member'] as $key=>$val){
var_dump(setcookie("member[{$key}]","",time()-3600));
}
session
Session技术与Cookie相似,都是用来存储使用者的相关资料,但是最大的不同之处在于cookie是将资料存储在客户端电脑中,而session则是将数据存放于服务器上。比如:银行有我们的信息,银行卡里也有我的信息,银行卡就相当于cookie,是一种身份。银行卡号可以称为session id,我们客户端的cookie中只需要保存session id(可以理解是一种唯一标识)即可。也就是说,我们银行卡上面有我们的卡号,通过卡号我们就可以去银行存款,取款。
通过session技术也可以使我们的数据更安全,因为他是保存在服务器端的,保留在客户端显得不安全。客户端只需要保存类似的卡号即可,你发送请求,带上卡号,服务器端通过卡号就可以查找你的信息,这些信息或许是非常敏感的信息,放在cookie显得不安全。就给你分配卡号。卡号对应的数据就在服务器端上。这就是session技术。
从上面讲的例子可以看出session依赖于cookie技术,因为session id存放于cookie中,所以cookie删了,session id也没了。
1. 开启session
<?php
session_start(); //开启一个会话(理解为去银行办银行卡),或者返回已经存在的会话(理解为已经办了银行卡,然后去存款)
//向服务器端存数据
$_SESSION['name']='xiaochen';
$_SESSION['email']='xxxxx@qq';
以上是一个页面,现在我们在新建一个页面。
<?php
session_start(); //属于第二种情况,打开已经存在的会话,根据客户端传来的session id吧这个session id对应的数据读取到$_SESSION这个变量里面,不然$_SESSION是没有内容的。
var_dump($_SESSION);
var_dump($_COOKIE); //可获取到session id;属性是PHPSESSID(session名),可以在php.ini中定位到session.name这个属性上,看它的值是不是PHPSESSID,根据情况而定。
那么这些数据存放在服务端的那个位置呢?打开php.ini,定位到session的位置,找到session.save_path属性,值就是它的保存位置。
2. 销毁session
<?php
session_start();//打开要销毁的会话
session_unset(); // 释放所有session变量
session_destroy(); //销毁一个会话的全部数据,会把你存在服务器上的文件也干掉。
//setcookie('PHPSESSID','',time()-3600); //相当于把卡号也删了。第一个参数直接写PHPSESSID就把session的名字写死了,因为我们可以改配置里的session.name这个属性的值,所以不行,哪有没有一个函数可以代替呢?答案是有的,哪就是session_name();获取session的名字,同理,也有session_id()是读取/设置当前会话的,也有读取的意思。
setcookie(session_name(),'',time()-3600); //销毁客户端的session id,但是这样并不能删除成功。为什么呢?
//注意点:使用setcookie删除cookie的时候,需要与当初设置cookie的时候参数一致,
//因为它有第四个参数,是路径,表示设置的cookie在哪里有效,比如你写了/abc/,就表示在localhost/abc/下面的所有文件都有效,比如localhost/abc/a/b/,它在abc目录下有效,如果是/哪就说明在localhost下面的全部有效。在php.ini定位到session.cookie_path看看它的有效目录是什么?发现它是/ 根目录,表示localhost下面的整个目录都是有效的。如果我们不指定第四个参数,那么它默认是什么?默认是当前目录下,如/demo/,其实就是localhost/demo/ ,变成了只针对demo下面的有效,与php.ini不符,所以我们在删除cookie的时候才不成功。所以把第四个参数传一个/就ok了。
setcookie(session_name(),'',time()-3600,'/');
34. 排序
34.1 排序的简单概述
排序是将一组数据,依指定的顺序进行排列的过程。你要么从大到小排,要么从小到大排。排序分为内部排序和外部排序,内部排序是指将需要处理的所有数据都加载到内存中进行处理。外部排序法是数据量过大,无法全部加载到内存中,需要借助外部存储进行排序。我们今天讲的是内部排序法。
内部排序分为"交换式排序法",“选择式排序法”,“插入式排序法”。
交换式排序法又分为冒泡排序法,和快速排序法。
34.2 冒泡排序
如下图:
还是那句话,9人比拼,每一轮淘汰一人,那要进行几轮?是不是进行8轮?留到最后的1人就是胜利者,还需要进行第九轮吗?名次就按从左往右排,第一个淘汰的肯定是放在最右边啦!!
34.3 选择排序
基本思想是一个数组中我假设第一个元素是最小的,然后让第一个元素与后面的元素对比,找到最小的,如果找到比第一个元素还小,就会跟第一个元素交换位置,然后退出游戏,依次类推,到第二个元素假设最小,跟后面一一对比找到比第二个元素还小的,然后跟第二个元素交换位置,然后第二个元素退出游戏,这样一直下去,如果数组是8个数,那要进行7轮匹配。
上图的最后一句话说错了,第二个循环只是找出最小的元素,并打上标签,不包括交换位置。
<?php
$arr = array(4,7,8,1,0,-2);
//以上数组里的元素是乱的,我们接下来用选择排序来解决它。
$temp=0;
for ($i=0;$i<count($arr)-1;$i++)
{
$minVal=$arr[$i]; //假设第一个元素是最小值
$minIndex=$i; //与上面对应,这是记录最小值的索引
//以上两句代码都是为最小值打上标签的。
//下面是每一轮的循环
for($j=$i+1;$j<count($arr);$j++)
{
if($minVal>$arr[$j])
{
$minVal=$arr[$j];
$minIndex=$j;
}
}
//一轮结束后交换位置
if($minVal<$arr[$i]){
$temp=$arr[$i];
$arr[$i]=$arr[$minIndex];
$arr[$minIndex]=$temp;
}
}
print_r($arr);
?>
34.4 插入排序
准确的说,是一个数组分为有序表和无序表两种,无序表中会取出第一个元素,插入到有序表中的适当位置,成为新的有序表,以此类推。
<?php
$arr = array(3,4,1,8,2,5);
//以上数组里的元素是乱的,我们接下来用插入排序来解决它。 从小到大排
for($i=1;$i<count($arr);$i++) //数组中索引为1,2,3,4,5的这五个索引都遍历到了。
{
$insertVal = $arr[$i]; //无序列表的第一个元素被$insertVal变量保存起来
$insertIndex = $i-1; //跟前面的一个数比较
//下面的while循环就是找位置
while($insertIndex>=0 && $insertVal<$arr[$insertIndex])
{
//同时把数后移
$arr[$insertIndex+1]=$arr[$insertIndex];
$insertIndex--;
}
//插入(这时就给$insertVal找到适当位置)
$arr[$insertIndex+1]=$insertVal;
}
print_r($arr);
?>
34.5 快速排序
拿到一个数组,用数组的最后一个元素作为基准点,除了基准点外剩下的元素两个各位一个左右标记,左标记筛选比基准点大的数,右标记筛选比基准点小的数字,在移的过程中左标记先移,从左往右移,右标记从右往左移,左标记移到比基准点大的数后停下来,然后右标记移到基准点小的数停下来,然后左标记对应的数与右标记对应的数交换,然后接着左标记继续下移,与上面同样的操作,直到两个标记重合,重合后两个标记所指向的数字与基准点比对,如果所指向的数字比基准点小,那没必要交换,如果大,就交换,这样第一轮排序结束,以基准点为分界线,左右一边,对左右各一边应用上面同样的操作。
怕有些人搞不懂,下面有个练习,就是我对它的排序,如图:
总结
从上面讲的四个排序算法,不知道你们掌握了没有,可能快速排序自我感觉会有点难,但是还好,最重要的要掌握它的思想,代码不会没关系,四种排序算法最重要的是前三个,所以前三个尽量保证自己会把它敲出来。然后这前三个排序算法从效率来看是依次递增的,也就是说冒泡发的效率是最低的。但不是说冒泡就没用处了,可能在某些场景下优化一下效率还是高的。快速排序法它对于大数据量对它们排好序的速度是很快的,比前三个都快,但不能说它效率高,因为效率用从两方面考虑,时间和空间,快速排序法其实是空间换取时间,它特别费空间,虽然时间快。快速排序法其实是一个递归,你想,我们在学函数递归的时候,递归就是自己调自己,每调一次,是不是要开辟一个栈,是不是费空间呀!!当然了,如果你内存够大,哪没问题,无所谓。在面对用户时,是时间重要还是空间重要?显然是时间重要,不然用户一直卡着,体验及差,那就会损失很多用户。所以很多时候,人们更愿意牺牲空间换取时间,但如果能节省空间那就更好了。
35. 查找
查找分为顺序查找(对某个数组,按照顺序,一个一个比较,然后找到你要的数据),例子:要求从一个数组$arr=array(46,90,900,0,-1)查找一个数34,找到返回索引,否则返回"查无此数"。如下代码:
<?php
$arr = array(349,90,400,0,-1);
$findVal=34;
$flag=false;
for ($i=0;$i<count($arr);$i++)
{
if($findVal==$arr[$i])
{
echo "找到了,下标为$i";
$flag=true;
break;
}
}
if(!$flag)
{
echo '查无此数';
}
?>
上面不是重点,重点是接下来的二分查找法
35.1 二分查找
代码copy:
<?php
$arr = array(1,90,900,999,1234);
function binarySearch(&$arr,$findVal,$leftIndex,$rightIndex)
{
if($rightIndex<$leftIndex){
echo "找不到该数";
return;
}
$middleIndex=round(($rightIndex+$leftIndex)/2);
if($findVal>$arr[$middleIndex])
{
binarySearch($arr,$findVal,$middleIndex+1,$rightIndex);
}elseif ($findVal<$arr[$middleIndex]){
binarySearch($arr,$findVal,$leftIndex,$middleIndex-1);
}else{
echo "找到这个数 下标是: $middleIndex";
}
}
binarySearch($arr,90,0,count($arr)-1);
?>
36. json处理
json主要用来跟后端进行通信,是一种数据交换格式。
数组是一种数据格式,那么json也是一种数据格式:
php的数组的数据格式: ["name"=>"zhangsan","age"=>15];
json的数据格式:{"name":"zhangsan","age":15};
总结:
json_encode():将数组或对象转为json
json_decode():将json转为数组或对象
版权声明:本文标题:PHP自学笔记(基础语法篇) 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/xitong/1728026177a1142682.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论