PHP学习笔记1
PHP基础
1、PHP介绍
PHP是一种运行在服务器端的HTML脚本/编程语言,主要作用是编写动态网页。PHP的底层语言是C语言,与Python类似,PHP的很多功能是由加载拓展实现的。
2、PHP环境搭建
1、下载PHP
PHP的目录结构主要有:PHP解释器、PHP拓展包、PHP配置文件:development 开发板 production 生产板、和php.exe。
其中php.exe的作用为解析php代码转变为HTMLd代码,从而让浏览器可以解析,操作方式为:
打开命令行终端,移动到PHP所在路径,输入 php.exe -f 所需要解析的PHP文件路径
2、web服务器加载PHP模块
1、加载PHP模块
在Apache的主文件中加载PHP提供的模块,在Apache的httpd.conf文件中LoadModule中配置:
LoadModule php版本号_module PHP所提供的模块链接所在路径
2、Apache分配工作给PHP模块
通过文件后缀来分配,在httpd.conf中添加:
AddType appliaction/x-httpd-php .php
3、将php配置文件加载到Apache配置文件中
在httpd.conf中加载PHP配置文件:
PHPIniDir PHP安装路径
php.ini文件默认不存在,是以development和production格式存在,需要格式化:
在PHP文件中找到php.ini-development,复制一份文件并将其后缀修改为.ini
因为上面的步骤已经将PHP已经被Apache加载,意味着php.ini修改需要Apache重启才能生效
3、PHP连接数据库
PHP本身不具备MySQL等数据库能力,需要借助PHP操作MySQL拓展
PHP加载MySQL拓展
在php.ini文件中,找到extension,去除mysql拓展前的封号,增加指定拓展所在路径
在php.ini文件中,找到extension_dir,增加拓展路径,即PHP中的ext文件
拓展是否配置成功使用phpinfo()函数确认
4、设定PHP系统时区
在php.ini中找到date.timezone,新增:
date.timezone = PRC(代表中国时区)
5、设置虚拟主机
如果只在一台服务器上只配置一个网站,那非常浪费,因此需要虚拟主机的技术,使得一台主机可以配置多个网站。
虚拟主机(Virtual machine):可以提供真实主机功能,但不是真的主机
在Apache中配置虚拟主机可以分为:
基于IP的虚拟主机:一台主机有多个IP,每个IP对应一个网站。实现:在一台主机上安装多张网卡,一张网卡绑定一个IP
基于域名的虚拟主机:一台主机只有一个IP,但一个IP下有多个网站,每个网站有不同的名字(虚拟主机名),用户需要在URL里表明名字让Apache进行匹配
3、PHP语法基础
1、PHP代码格式
PHP标记
PHP代码可以嵌入到HTML中,但为了让浏览器区分PHP脚本,需要将PHP脚本进行标记,标记的方式有:
ASP标记:<% php代码 %>
短标记:<? php代码 ?>
(以上两种基本弃用)
脚本标记:<script language="php"> php代码 </script>
标准标记(最常用):<?php php代码 ?>
PHP注释和分隔符
PHP的代码注释方式与C相同,行注释使用#或//,区块注释使用/*注释的内容*/
PHP语句使用;作为分隔符,让系统判断语句结束位置
2、变量
PHP中定义不需要关键字或赋值
如:$a
PHP中变量可以删除,用来释放内存,语法为:unset($变量)
PHP中的变量名必须以$开头,可以是$+字母、数字、下划线的组合,但不能以数字开头
PHP中还有一些预定义变量,即系统定义好的变量,用来存储用到的数据(预定义变量数值类型都为数组),自定义的变量名不能与这些预定义的变量重名,常用的预定义变量有:
$_GET:获取所有表单以get方式提交的数据
$_POST:GET提交的数据
$_REQUEST:GET和POST提交的信息
$_GLOBALS:PHP中所有的全局变量
$_SERVER:服务器信息
$_SESSION:session会话数据
$_COOKIE:cookie会话数据
#_ENV:环境信息
$_FILES:用户上传的文件信息
如果赋给一个变量的值刚好为另外一个变量的名,则这个变量为可变变量,可以在上一个变量前加一个$去调用另外一个变量
$a='b';$b='可变变量';echo ($$a);
3、常量
PHP定义常量的方式两种:
define('常量名',常量值)
const 常量名 = 常量值
常量命名不要在前加$,不然系统就认为这个是变量,常量的命名规则与变量基本相同,一般为全大写字母为主,但也可以使用特殊符号,但名字有特殊符号的常量只能用define命名。常量的命名一般不区分大小写(可以通过define区分,但不推荐)
常量一般可以直接访问,但名字为特殊符号的常量需要用constant来访问
系统帮助用户定义了一些常量,叫做系统常量,用户可以直接使用,例如:
PHP_VERSION:PHP版本
PHP_INT_SIZE:int类型所占字节
PHP_INT_MAX:int类型能表示的最大值
PHP中还有些常量称为魔术常量,其值会随着环境改变而改变,但用户无法改变,魔术常量命名一般以双下划线+常量名+双下划线
4、数据类型
PHP中的数据类型与C一致,有:
简单数据类型
整形:int/integer,4字节,整形如100这种数字表示十进制,前面加0b,如0b100表示是二进制,前加0,如0100表示是八进制,前加0x,如0x100表示是十六进制,PHP默认输出都自动转换为十进制
浮点型:float/double,8字节(也可存储整形存不下的整数)
字符串型:string
布尔型:bool/boolean
复合数据类型
对象类型:object
数组类型:array
特殊数据类型
资源类型:resource
空类型:NULL(不可运算)
PHP中的类型转换方式有两种:
自动转换:
系统根据自己需求转换,例如,布尔值false值为0,true值为1;字符串以在字母开头值为0,以数字开头值为在第一个字母前的数字大小;
强制转换:
语法为:(数据类型)变量,若要将变量转换为NULL类型,则需要unset()
PHP可以用语句判断数据类型,方式为:
is_数据类型(变量名),如果一致则返回ture,否则返回false
gettype(变量名),返回与变量一致的数据类型的字符串
settype(变量名),设置变量数据类型,与强制转换不同,强制转换只是单纯对原数据值进行处理,不改变原来变量指向的值,而settype直接改变变量指向的值
5、运算符
PHP的运算符包含赋值、算数、逻辑运算符等,还包括:
连接运算符,将字符串进行拼接的符号
. :将两个字符串拼接
.=:将两个字符串拼接并重新赋值给左边
错误抑制符:添加到一段代码前,若产生错误则不进行报告
@:在代码前加@
6、分支结构
PHP中的分支语句包括if和switch语句
if语句语法为:
if(条件表达式1){
执行的代码;
}
elseif(表达式2){
执行的代码;
}
……
else{
执行的代码
}
switch语句的语法为:
switch(条件表达式){
case 值1:
需要执行的代码;
break;
case 值2:
需要执行的代码;
break;
……
default:
需要执行的代码;
break;
}
7、循环结构
PHP循环结构语句有:for语句、While语句、do-while语句
for循环的语法为:
For(初始化语句;结束循环判定语句;条件变化语句){
循环执行的代码;
}
while循环的语法为:
While(条件表达式){
循环执行的代码
}
do-while循环语法为:
Do{
循环结构;
}while(条件执行语句);
循环可以通过continue和break来进行循环控制
由于PHP是内嵌到HTML里的代码,如果直接在HTML里写原来的流程控制语句会不美观,因此PHP提供了一种代替机制可以不使用大括号
左大括号{:用冒号替代
右大括号}:用end+对应的控制语句替代
<!--不使用代替语句输出九九乘法表--><p>九九乘法表</p><table border=1><?php $x=1; ?><?phpfor($i=1;$i<10;$i++){ ?><?php $j=0; ?></tr><?php for($j=$x;$j< 10;$j++){ ?><td><?php echo $i."X".$j."=".$i*$j;?></td><?php }?></tr><?php $x++; ?><?php } ?></table>
<!--使用代替语句输出九九乘法表--><p>九九乘法表</p><table border=1><?php $x=1; ?><?phpfor($i=1;$i<10;$i++): ?><?php $j=0; ?></tr><?php for($j=$x;$j< 10;$j++): ?><td><?php echo $i."X".$j."=".$i*$j;?></td><?php endfor;?></tr><?php $x++; ?><?php endfor; ?></table>
8、文件包含
文件包含指在一个PHP脚本中,将另外一个文件(PHP)包含进来,实现代码的重用。让多个脚本协作完成一项工程。在PHP中被包含的文件是单独编译的
PHP中文件包含有四种形式,分别为:
include:包含文件,系统碰到一次执行一次
include_once:系统判断包含的文件之前是否被包含过,限定一个文件只能被执行一次
require:与include一致
require_once:与include_once一致
require与include使用基本一致,区别在于如果包含文件的代码如果错误,require报错形式与include不一样,include包含文件代码出错,则会不执行包含文件但继续往下执行代码,但require包含文件代码错误,则不再执行require以后的代码
9、函数
PHP中函数语法格式如下:
function 函数名(参数){
函数体;
}
静态变量
PHP中可以使用static修饰变量,用于实现跨函数数据共享,函数在调用时,会自动跳过static这一行。静态变量可用于:统计函数被调用的次数;统筹函数在第几次调用时的结果(递归函数里常用)
可变函数
一个变量所保存的值与一个函数名相同,则这个函数称为可变函数,可以使用变量名+()去调用该函数
回调函数
将一个函数作为参数传给另外一个函数,则这个函数称为回调函数
闭包
若一个父函数内部有子函数,子函数为匿名函数,若使用use(变量名),将子函数之外父函数的变量给子函数使用,这个过程称为闭包
伪类型
实际上不存在与PHP的类型,见于操作手册,用于辅助理解的,伪类型包括:
Mixed:混合类型,代表PHP中的所有类型
Number:数值类型,可以是整形或浮点型
系统常用函数
系统常用函数有:
print():输出函数,与echo类似本质是一种结构,不是函数,返回1,括号可不加
print_r():与var_dump类似,只会输出值,不会输出数据类型
date():按照指定格式对应的时间戳(从1970年1月1日0时0分0秒起到目前或指定时间事件的秒数)
time():获取当前时间的时间戳
microtime():获取微秒级别的时间
strtotime():将指定格式表示时间的字符串转换为时间戳
max():指定参数中最大的值
min():指定参数的最小值
rand():得到一个指定区间的随机整数
mt_rand():与rand()一样,但效率更高,建议使用这个
ceil():向上取整
floor():向下取整
pow(a,b):取a的b次幂
abs():绝对值
sqrt():求平方根
function_exists():判断指定函数名字是否在内存中存在,增加代码安全性
func_get_arg():在自定义函数中获取指定数值对应的参数
func_get_args():获取自定义函数的所有参数
func_num_args():获取自定义函数的参数数量
10、错误处理
在开发中需要完全反馈错误信息,以调试代码,而在实际生产环境中,根据最小化反馈信息的原则,一般需要不抛出或只抛出一点点错误信息,而又要保存错误日志让后台的程序员去修改,那需要配置PHP文件或者在代码中使用ini_set设置。配置设置方法为:
在php.ini中找到log_errors,将其赋值为on
找到error_log,指定错误日志保存路径
也可以自定错误处理:
PHP系统提供了一种用户处理错误的机制:用户自定义错误处理函数,将该函数增加到系统错误句柄中,系统读到错误时,会使用用户的函数,将用户自定义的函数放到系统中(set_error_handle)的步骤为:
自定义错误函数
其中包括五个参数(变量名建议与操作手册的命名一样):errno:错误代号;errstr:错误提示;(前两个自定义函数中必须存在)errfile:错误文件路径;errline 发生错误的代码位置;errcontext
注册自定义函数,修改错误机制
set_error_handle(自定义函数)
<?php //自定义错误函数 function my_error_handler( $errno, $errstr, $errfile, $errline) {if(!(error_reporting()&$errno)){return false;}//首先将系统本不会处理的报错排除在外switch($errno){case E_ERROR:echo"系统错误";break;case E_WARNING:echo "系统警告";break;case E_USER_ERROR:echo "用户错误";break;case E_USER_WARNING:echo "用户警告";break;default:echo "其他错误";}//然后对于报错分别处理}$a;echo $a;set_error_handler('my_error_handler');//将自定义错误放入系统echo $a;?>
11、字符串
字符串可以用单引号或双引号定义,这种定义方式适合不超过一行或者没有结构的字符串,若是定义长字符串或者有结构的字符串可以用一下两种结构化方式定义:
heredoc结构,相当于双引号结构:
变量=<<<边界符
字符串
边界符
nowdoc结构,相当于单引号结构:
变量=<<<‘边界符’
字符串
边界符;
结构化定义字符串规则:
上边界符不能跟任何内容
下边界符必须顶格,且后边不可跟任何内容
转义字符
PHP中也有转义字符,一般为\后加转义符号,单引号字符串无法转义\',而双引号字符串无法转义\"
双引号定义的字符串可以识别$从而可以解析变量,但单引号不行
字符串常用函数
strlen():得到字符串的字节数(中文占用3字节)
加载mbstring拓展,可以得到很多关于字符串的函数:
mb_string:获得不同字符集下多字节字符串的长度(需要指定字符串格式)mb_string(字符串,格式)
implode():将数组中的元素按照指定规则连接成字符串;implode(连接方式,数组)
explode():将字符串按照指定格式分割成数组;explode(分割字符,字符串)
str_split():将字符串按照指定长度分割成数组;str_split(长度,字符串)
trim():去除字符串两边的空格,也可以指定去除两边指定的内容,直到碰到第一个非目标字符
substr():截取指定位置和指定长度的字符串
strtoupper():将字符全转换为大写
strtolower():将字符串全转换为小写
uc_first():将字符串首字母转换为大写
strpos():查找指定字符在字符串中首次出现的位置,若没找到则返回false
strrpos():查找指定字符在字符串中最后一次出现的位置,若没找到则返回false
str_replace():将字符串指定字符替换为指定的其他字符;str_repalce(指定字符,替换字符)
printf()/sprintf():格式化输出字符串;sprintf(输出的包含占位符的字符串,占位符对应的变量)
str_repeat():重复字符串N次
str_shuffle():随机打乱字符串
12、数组
PHP中提供了多种定义数组的方法:
$变量=array(元素1,元素2,……);或者array(key1=>value1,……);
$变量=[元素1,元素2,……];
隐形数组:$变量[]=值1;$变量[下标]=值;//下标可以是字母、数字,若不提供下标,则系统自动从0开始标
PHP的数组有自己的一些特点:
PHP数组可以是整数下标或者字符串下标,也可以同时有字母和数字,纯数字下标的数组称索引数组、纯字母下标的数组称关联数组、字母数字下标的数组称混合数组,数组的元素顺序与放入数组的顺序为准,与下标无关
PHP数组拥有自增长特性,默认从0开始+1增长,但若中间手动添加一个较大下标,则按最大的数开始自动增长
PHP数组的下标相当于JS或python里字典的键名,下标对应的元素相当于键值
特殊字符不可用作下标,若用成下标则会自动转换,如false转换为0,true转换为1,NULL转换为空字符串
PHP数组没有类型和长度限制
多维数组
二维数组的定义方法可以是:
array(
array(),
array(),
……
);
多维数组
指第二维的元素还是数组,PHP数组没有维度限制(因为PHP的数组不是真正意义上的数组),但不推荐超过三维
异性数组:
数组元素不规则,有是数组也有不是数组的(可以,但不常见)
数组遍历
因为PHP数组下标不规则,所以需要一些简化规则自动获取下标并访问元素
使用foreach遍历,语法为:
foreach($数组变量 as [$下标=>] $值){};索引数组一般无需获取下标,而关联数组一般要获取下标
foreach的原理是利用数组内部的指针,该指针默认指向第一个元素,在利用指针获取数据的同时移动指针,如果之前操作过指针,foreach会将指针重置到指向第一个元素,
使用for循环遍历数组,for循环遍历要求数组元素下标必须是规律的数字,语法为:
for($i=0;$i<count(数组);i++){}
使用while+each或list遍历
each函数(PHP7.2之后弃用):可以从一个数组中获取当前指针指向的数组下标和值,并以一个四个元素的数组返回,如果数组指针指向数组最后,则返回false分别为:
0下标->取得元素的下标值
1下标->取得元素的值
key下标->取得元素的下标值
value下标->取得元素的值
list函数:是一个结构,因此没有返回值,list提供一堆变量,依次取得数组的元素,并赋值给这些变量,list只能从索引数组获取数据,且数组第一元素的索引必须是0
语法为:
list($变量1,$变量2,……);list中变量个数必须小于等于数组
$arr = array(1,'name'=>'tom','age'=>18);foreach ($arr as $k => $v) {echo''. $k .''. $v .'';}echo'<br>';$nums = [0,1,2,3,4,5,6,7,8];for($i = 0; $i < count($nums); $i++) {echo $i;}echo '<br>';
数组函数
常见的数组函数有:
排序函数:也可以排序字符串,按字符串首字母的Ascall码值进行排序
sort():将数组元素顺序排序,会改变原元素的下标
rsort():将数组元素逆序排序
asort():将数组函数顺序排序,不改变原元素下标
ksort():按照数组键名(下标)顺序排序
krsort():按照数组键名(下标)逆序排序
shuffle():随机打乱数组元素
指针函数:
reset():将数组指针回到指向第一个元素
end():将数组指针拨到指向最后一个元素
next():将数组的内部指针下移一位,返回下一个指向元素的值
prev():指针上移,取得上一个元素值;next和prev可能导致指针移除数组且语法移回,此时需要end或reset重置指针
current():取得当前指针指向的元素值
key():获取当前指针指向的元素下标
其他函数:
count():统计数组中元素的数量
array_push():往数组末尾加入一个元素
array_pop():取出数组末尾的元素
array_shift():取出数组头部的元素
array_unshift():往数组头部加入一个元素
array_reverse():将数组转置
in_array():判断一个元素是否在数组中
array_keys():获取一个数组所有下标,返回一个索引数组
array_values():获取一个数组所有值,返回一个索引数组
13、算法基础
递推算法
递推算法是指通过已知条件,利用特定关系得出中间结论,直至得到结果,递推算法有顺推和逆推两种
顺推:通过已知条件推演结果
逆推:通过已知结果,得到条件
递归算法
递归算法就是讲一个问题转换为多个同类问题的子问题,然后调用函数表示问题的解,递归函数指函数的返回值是函数本身
递归算法分为以下几步:
简化问题:找到最优子问题,即不可再缩小范围的问题
调用函数:让函数自己调用自己
当一个问题可以用递归函数解决时,那么这个问题一定有两个点:
递归点:发现当前问题有一个小一点的子问题,可以用函数解决
递归出口:当问题解决时,已经到达最优子问题,可以设立递归结束条件结束递归,在写代码时先写递归出口
递归的优缺点:因为会同时调用N多个函数,因此会占用内存,但执行更快,是一种空间换时间的方法
例如斐波那契数列、爬楼梯等问题都用到递归
<?php//爬楼梯问题,设有一个台阶,可以一次爬一级,也可以一次爬两级,当一个台阶阶数为n时,请问总共有几种爬法//找规律,当台阶的阶数和方法数关系对应为:/*1 12 23 34 5……*///发现,到第N阶楼梯的方法数F(N)等于前N-1级台阶方法数F(N-1)和前N-2级台阶方法数F(N-2)的和,直到拆分到N=2和N=1为止//例如,一个9级台阶的方法数等于8级台阶和7级台阶的和,8级台阶等于7级台阶和6级台阶的和……//这样可以写函数function stair($n){if($n===1){return 1;}elseif($n===2){return 2;}//先写递归中止条件,即递归出口return stair($n-1)+stair($n-2);//在写递归点,即将这个大问题分割为小问题的方法}echo stair(3);?>
排序算法
排序算法有冒泡排序、选择排序、插入排序、快速排序和并归排序
冒泡排序
冒泡排序属于简单的排序算法,重复走过需要排序的数列,一次比较两个元素,如果顺序错误则交换两个元素的位置,每一次能确定一个最大/最小的泡,放置在数组末尾,之后对剩余元素重复以上步骤,直到没有任何一对数字顺序错误
//冒泡排序function bubble_rsort($array){for($i= 0;$i<count($array);$i++){for($j=0;$j<count($array)-1;$j++){if($array[$j]<=$array[$j+1]){$x=$array[$j];//交换两个元素的值,创建一个中间变量方便交换$array[$j]=$array[$j+1];$array[$j+1]=$x;}} }return $array;}//将一个数组从大到小排列$arr=[1,4,6,9,1,2,5,7,9,1];print_r(bubble_rsort($arr));
选择排序
比冒泡排序效率更高的一种排序方法,用到选择函数,初始假设数组中数组最前端的元素A为数组中最大/最小的一个元素,然后继续寻找右侧剩余数组元素比较,如果出现比A小的元素B,则认为新的最小的元素为B,之后再和右侧剩余元素比较。选择排序也是最不稳定的一种排序方法,即相同值的元素下标会不停变动。
//选择排序function select_sort($array){for($i=0,$len=count($array);$i<$len;$i++){$max=$i;//初始假设最大的数为array[$i]for($j=$i+1;$j<count($array);$j++){if($array[$j]>$array[$max]){$max=$j;}//循环找出一个数组中下标i之后的最大的数的下标}//如果$i的值不等于$max的值则交换当前值if($i!=$max){$mid=$array[$i];$array[$i]=$array[$max];$array[$max]=$mid;}}return $array;}$arr1=[1,4,6,9,1,2,5,7,9,1];print_r(select_sort($arr1));
插入排序
插入排序是一种比选择排序更加稳定的排序方法,其思路为i从0开始,将第i+1个元素插入到前0-i个元素中
//插入排序function insert_sort($array){for($i= 1;$i<count($array);$i++){//假设第一个元素已经排好$temp = $array[$i];//从第i+1个元素开始,插入到对应的位置for($j=$i-1;$j>=0;$j--){if($temp>$array[$j]){//如果要插入的元素小于arr[$j],则将arr[$j]后移一位,中间插入该元素$array[$j+1]=$array[$j];$array[$j]=$temp;}}}return $array;}$arr2=[1,4,6,9,1,2,5,7,9,1];print_r(insert_sort($arr2));
快速排序
快速排序是冒泡排序的改进,用到的是递归的方法,也是一个不稳定的排序算法,算法思路为:先取出数组中的一个元素,然后定义两个数组,比该元素小的数组放在一个数组,比该元素大的放在另外一个数组,这样虽然前后数组顺序不确定,但确定了第一个元素所在的位置,之后将两个数组递归,重复上面的步骤直到数组中只有一个元素,回溯最小数组
//快速排序function quick_sort($array){if(count($array)<=1){return $array;}//设置递归出口$left=$right=array();//创建两个数组,一个大一个小for($i= 1;$i<count($array);$i++){if($array[0]<=$array[$i]){$left[]=$array[$i];}else{$right[]=$array[$i];}} //将比第一个元素大的数放在left中,将比第一个元素小的元素放在right中//继续对两个数组进行以上操作$left=quick_sort($left);$right=quick_sort($right);return array_merge($left,(array)$array[0],$right);}$arr3=[1,4,6,9,1,2,5,7,9,1];print_r(quick_sort($arr3));
归并排序
并归算法是一种与快速排序效率差不多的算法,其思路为将一个数组不断进行二分拆解,直到数组里只有1-2个元素,此时数组是有序的,然后使用二分并归法将数组合并。
//归并排序function merge_sort($array){if(count($array)<=1){return $array;}//设置递归出口$len=count($array);$middle=floor($len/2);//将数组进行二分化$left=array_slice($array,0, $middle);$right=array_slice($array, $middle);$res=array();//创建一个新数组$left=merge_sort($left);$right=merge_sort($right);//设置递归点while(count($left)&& count($right)){$res[]=$left[0]>$right[0]? array_shift($left):array_shift($right);}//对数组进行二分并归return array_merge($res,$left,$right);}$arr4=[1,4,6,9,1,2,5,7,9,1];print_r(merge_sort($arr3));
查找算法
查找算法用于寻找数组中有无匹配项,其算法有顺序查找和二分查找
顺序查找
遍历所有数组中的元素,直到有与查找元素匹配的元素或遍历到数组末尾,有则返回数组下标,没有则返回false
二分查找
用于在有序数组里查找元素,其算法思路为:定边界,一开始为最左边和最右边,比较两个边界中间的元素与查找元素的关系,如果大,则下次的左边界为中间+1的位置,如果小,则下次的右边界为中间+1,重复上述过程,直到找到元素或者左边界值大于等于右边界值