#### 第15章:
#### PHP
PHP初始全称为Personal Home Page,现已正式更名为Hypertext Preprocessor(超文本预处理语言)。PHP算一种HTML内嵌式的语言,在服务端执行的嵌入HTML文档的脚本语言,语法风格类似C语言,被广泛应用于动态网站制作中。PHP支持各种数据库和操作系统,还能使用C/C++进行程序扩展。
#### 15.1 PHP7的准备工作
##### Nginx 和 PHP 7 服务器安装配置
1. ##### 获取PHP7安装包资源
- 打开浏览器,进入https://www.php.net/downloads
:-: ![](https://img.kancloud.cn/f5/79/f57957c7c69d4c0a08cbe1f873bfabeb_1749x733.png)
- 选择合适的版本,这里选择PHP7版本
- 选择合适的格式,这里选择tar.gz格式
:-: ![](https://img.kancloud.cn/8c/cf/8ccf2f67916f79493ed8462a0a73381f_735x338.png)
- 复制其地址,使用wget命令下载到服务器。
:-: ![](https://img.kancloud.cn/d4/f8/d4f81d3041b1845d131b3435798e72d0_1406x242.png)
1. ##### 获取Nginx安装包资源
Nginx是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。其特点是占有内存少,并发能力强。
- 打开浏览器,进入http://nginx.org/en/download.html
:-: ![](https://img.kancloud.cn/4b/64/4b648dbe5671e0c7cccbb00ec1b53e86_1208x872.png)
- 选择适合的版本,这里选择1.16
- 选择适合的格式,这里选择tar.gz
:-: ![](https://img.kancloud.cn/1b/97/1b97f62458d3354b6fc898f65c065010_639x176.png)
- 复制其地址,使用wget命令下载到服务器。
:-: ![](https://img.kancloud.cn/29/6a/296a1eb3ab691b0379982628d5d09ef8_1397x190.png)
2. ##### 安装Nginx和PHP
- 使用tar命令解压nginx压缩文件
- 进入nginx文件夹使用`./configure --prefix=/usr/local/nginx`构建安装nginx到/usr/local/nginx目录。再使用`make && make insgall`进行安装(安装过程中可能缺少依赖,使用yum进行安装)。
- 使用tar命令解压PHP压缩文件
- 进入PHP文件夹使用以下命令构建安装(构建安装路径、配置文件路径、功能模块等)
```
./configure --prefix=/usr/local/php7 \
--with-config-file-path=/usr/local/php7/etc \
--with-config-file-scan-dir=/usr/local/php7/etc/php.d \--enable-mysqlnd \
--with-mysqli \
--with-pdo-mysql \
--enable-fpm \
--with-iconv \
--with-zlib \
--enable-xml \
--enable-shmop \
--enable-sysvsem \
--enable-inline-optimization \
--enable-mbregex \
--enable-mbstring \
--with-openssl \
--enable-pcntl \
--enable-sockets \
--with-xmlrpc \
--enable-zip \
--enable-soap \
--without-pear \
--enable-session \
--with-curl \
--enable-opcache
```
再使用`make && make install`进行安装(安装过程中可能缺少依赖,使用yum进行安装)。
3. ##### 建立Nginx和PHP之间的连接
在PHP和Nginx的架构里,用户请求到达服务器后先经过Nginx处理,再由Nginx通过fastcgi协议发送给PHP的进程管理器php-fpm,最后由php-fpm分配子进程来运行PHP程序。
:-: ![](https://img.kancloud.cn/4c/53/4c5352e092f003e7f5664aa0733fa8c7_600x282.png)
Nginx与php-fpm的交互过程
- 将PHP安装目录里的bin目录中的php、phpize、php-config三个二进制文件复制到/usr/local/bin目录,这一步是为了将这三个运行文件设置成常用命令。
- 将解压后的PHP源文件目录里的php.ini-development(配置文件)复制到PHP配置目录(etc目录),取名为php.ini。配置目录通过`php --ini`命令查看
:-: ![](https://img.kancloud.cn/bb/1f/bb1f81ec11525de24dd175f463395537_458x128.png)
配置文件目录为/usr/local/php7/etc
- 找到nginx配置文件,在Nginx安装目录的conf目录里。使用`vim nginx.conf`命令将以下注释打开并修改root后面指向的未来的网站目录。
```
location ~ \.php$ {
//这里是你未来的网站目录
root /data/wwwroot/;
//这里配置通过fastcgi与php-fpm通信的ip和端口
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
//这里要注释掉换成下面一种
#fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
```
- 在PHP安装目录里的etc目录里,将复制粘贴`php-fpm.conf.default`为`php-fpm.conf`。并将php-fpm.d目录里`www.conf.default`的内容复制到php-fpm.conf里。并确认[www]块的`listen = 127.0.0.1:9000`(确保php-fpm监听的是9000端口,这样才能和Nginx通信)。
:-: ![](https://img.kancloud.cn/5f/63/5f63fd4b19cc60dcbd38b39beea900e4_671x693.png)
合并后的php-fpm.conf配置文件
- 启动Nginx,在Nginx安装目录下的sbin目录里输入命令`./nginx`;启动php-fpm进程管理器,在PHP安装目录下的sbin目录里输入命令`./php-fpm`
此时在网站目录下创建名为index.php的文件
```
<?php
echo "hello world";
?>
```
此时浏览器输入服务器IP地址时,出现hello world说明环境配置成功。
#### 15.2 PHP的基本语法
##### PHP的标识符
PHP代码是以`<?php`开始,以为`?>`结束的。
```
<?php
echo "这是一行PHP代码";
?>
```
##### 编码规范
1. 指令分隔符:PHP代码的正常描述中,是一句为一个执行单位,而句是以`;`号结尾。
```
<?php
echo "这是一句代码,以为分号结尾";
?>
```
1. 空白符:PHP对各种情况下的空白进行忽略。利用空白可以增强代码的可读性和清晰性。
2. 注释:为了增强可读性,程序员需要对代码添加文字说明。这就使用到了注释。
```
/*这是C语言的注释风格*/
```
- C语言的注释风格
```
//这是C++注释风格
```
- C++语言的注释风格
```
#这是SHELL的注释风格
```
- SHELL风格
3. 与HTML混搭
PHP可以与HTML文档混搭使用。
```
<html>
<head>
<title>PHP与HTML混搭</title>
</head>
<body>
<?php echo "HTML文档嵌入了PHP代码" ?>
</body>
</html>
```
#### 15.3 常量
常量是一类字面量,定义后就无法改变其值。
##### 声明常量
使用define()声明常量,通常使用大写英文字母表示。语法:
```
define('常量名','常量值');
```
常量可以存储数组、对象、字符、数字。例如:
```
<?php
define('NAME','星河一趟不枉双脚立行');
echo NAME;
?>
```
:-: ![](https://img.kancloud.cn/1f/d9/1fd9df2d84c4132adf2cbfe0aa178703_532x191.png)
运行结果
##### 内置常量
PHP内置了部分常量。用以随时调用。
1. `__FILE__`:文件的完整路径
2. `__LINE__`:PHP文件运行行数
3. `PHP_VERSION`:PHP程序的版本
4. `TRUE`:真
5. `FALSE`:假
6. `_DIR_`:文件所在目录
7. `PHP_OS`:运行PHP的系统
8. `E_ERROR`:最近错误处
9. `E_WARNING`:最近的警告处
10. `E_PARSE`:语法解析潜在问题处
11. `E_NOTICE`:发生不寻常但不一定是错误处
12. `_FUNCTION_`:函数名称
13. `_CLASS_`:类名
例子:
```
<?php
echo(__FILE__);
echo '<br>';
echo (__DIR__);
echo '<br>';
echo TRUE;
echo '<br>';
?>
```
:-: ![](https://img.kancloud.cn/8e/0e/8e0e5acb7edc2930f06e83cd94fb48ed_538x198.png)
运行结果
#### 15.4 变量
不同的变量类型对应着不同的数据类型。
##### 声明变量
不同于C/C++、Java等编译型语言在定义变量时需要指定变量的数据类型,PHP这种弱类型的语言只需要使用`$`符就可以定义任意数据类型的变量(实际交给了PHP底层进行数据类型的判断选择和空间申请等操作)。
合法的PHP变量以$为前缀,a~z的大小写或者`_`下划线开头。
合法的变量名可以是:
```
$name
$NAME
$Name
$_name
```
不合法的变量名:
```
$!1
$1name
```
PHP中对变量的赋值有传值和传址:
`传值`:直接将值赋予变量。
```
$name = '春夏';
```
`传址`:将地址空间传给变量,此变量得到此地址空间原变量的值,需加上`&`符号(取地址符号)。
```
$her = &$name;
```
##### 变量作用域
变量的作用域是指在代码中能访问到变量的范围。
1. 内置超全局变量:在代码中任何位置都可访问。
2. 常数:声明后为全局性,可以在函数内外使用。
3. 全局变量:可以在代码内访问,不可在函数内访问。
4. 函数内声明的全局变量(global关键字):在函数内部声明变量是全局变量就是同名的全局变量。
5. 函数内部创建和声明的静态变量:外部无法访问,静态值会保留。
6. 在函数中创建的局部变量:只能在函数内部访问,函数结束后释放。
`超级全局变量`是PHP内置的,在代码的任何地方都可以访问:
- $GLOBALS:包含全局变量的数组
- $_GET:通过GET方法传递来的变量的数组
- $_POST:通过POSET方法传递来的变量的数组
- $_COOKIE:包含cookie变量的数组
- $_SERVER:包含服务器环境变量的数组
- $_ENV:包含环境变量的数组
- $_SESSION:包含会话变量的数组
- $_FILES:包含上传变量的数组
全局变量例子:
```
<?php
$num = 3;
function showNum()
{
echo $num;
}
showNum();
echo $num;
?>
```
:-: ![](https://img.kancloud.cn/4f/5d/4f5d7785265233ce6378ee9ccd59fe64_534x203.png)
此时设置的全局变量$num在showNum函数内部是无法访问的。
静态变量例子:
```
<?php
$num = 3;
function addNum()
{
static $num = 10;
$num++;
echo '$num =' . $num . PHP_EOL;
}
addNum();
addNum();
```
:-: ![](https://img.kancloud.cn/38/90/3890d5b3225013303839e4f3131b656a_515x188.png)
此时函数将$num设置为静态变量值为10,调用两次+1,第一次输出11并保留其值,则再第二次调用时输出12。
##### 变量的销毁
当用户创建变量时,PHP底层处理逻辑会为变量分配一段内存空间,并对此空间进行引用计数(复杂数据类型),并引用计数+1。当其他变量被赋值为此变量或者此空间时,引用计数+1,当变量与该空间断开联系时,引用计数-1。引用计数是由PHP底层处理逻辑动态维护的。直到引用计数为0时,这块空间称为垃圾,也由PHP底层处理逻辑自动回收。
也可以使用unset()函数进行销毁,其用于切断变量名与分配空间的关联关系。unset()的例子:
```
<?php
$num = 10;
unset($num);
echo $num;
?>
```
:-: ![](https://img.kancloud.cn/14/45/1445e9310056e1a90c881a40da0b7660_526x196.png)
此时$num变量已经被切断与原来分配空间的关系,所以输出这个没有的变量会提示未定义变量num。
#### 15.5 数据类型
PHP变量不需要事先声明,赋值即可声明。PHP7的数据类型包括:
1. 字符串
2. 整型
3. 浮点型
4. 数组
5. 对象
6. NULL
7. 布尔
8. 资源(用于打开文件、数据连接、图形画布)
##### 字符串
字符串存储的是一段字符,例如:
```
$str = "hello world";
```
##### 整型
整型存放整数,例如:
```
$num = 1000;
```
##### 浮点型
浮点型表示实数,例如:
```
-1.43
1E+09
0.0
```
##### 数组
数组通过list()或者array()创建,或直接赋值。存放一组变量集合,由"键"与"值"的对应关系组成。数组元素可以是整数、字符串等。不指明"键"的情况下,默认"键"从零开始。
```
<?php
$arr = array(
0=>"张三",
1=>"春夏",
2=>"秋冬"
);
for($i = 0; $i<count($arr);$i++){
echo $arr[$i]."</br>";
}
?>
```
:-: ![](https://img.kancloud.cn/c5/b3/c5b3d03969409b90df19ee1705e1771f_515x187.png)
##### 对象
对象是类的实例。当一个类被实例化后,这个对象传递给一个变量,这个变量就是对象类型。
##### NULL
NULL类型是仅有NULL这个值。标记一个变量为空。
##### 资源类型
资源类型表示PHP的扩展,可以是一个打开的文件,也可以是一个连接或者其他。
##### 数据类型自动转换
数据类型从一个类型转换到另外一个类型就是数据转换。常见强制类型转换和自动转换。
##### 自动数据类型转换
```
<?php
$a = 1;
$b = '1';
$c = $a + $b;
echo $c;
?>
```
:-: ![](https://img.kancloud.cn/d4/ba/d4ba2f2836f3876e94923067c89e84b8_535x194.png)
##### 强制类型转换
在PHP中使用settype()或者(int)、(string)、(float)、(double)、(real)等函数可以实现强制类型转换。
```
<?php
$flo1 = 1.11;
echo settype($flo1,'int');
echo (int)$flo1;
?>
```
:-: ![](https://img.kancloud.cn/68/79/6879b596caff3a41629b0aaea675091b_519x186.png)
##### 标量类型的声明
默认情况下PHP文件处于弱类型校验模式。PHP7新增了标量类型声明的特性,标量声明有两种模式:强制模式(默认)和严格模式。语法:
```
declare(strict_types=1);
```
strict_type为1指严格模式,作用于函数参数和函数返回;strict_type为0指强制模式,会校对函数参数的数据类型和返回值的数据类型。
强制模式:
```
<?php
function maxNum(int $a, int $b)
{
if($a>$b){
echo $a;
}else{
echo $b;
}
}
maxNum(1,2.1); //这里会将2.1强制转换成2
?>
```
:-: ![](https://img.kancloud.cn/70/5e/705e1a2992a2796e5be8b18e515aebb2_517x195.png)
严格模式:
```
<?php
declare(strict_types=1);
function maxNum(int $a, int $b)
{
if($a>$b){
echo $a;
}else{
echo $b;
}
}
maxNum(1,2.1); //这里2.1不属于int整型,会报错
?>
```
:-: ![](https://img.kancloud.cn/9a/ed/9aed2508984dbd1c21ad41ea717142e4_523x255.png)
#### 15.6 运算符
##### 算数运算符
| 运算符 | 作用 | 运算符 | 作用 |
| ------ | ---- | ------ | ---- |
| + | 加法 | % | 取余 |
| - | 减法 | ++ | 累加 |
| * | 乘法 | -- | 累减 |
| / | 除法 | | |
常见的算数运算符
##### 字符串连接符
`.`号可以把两个不同的字符串连接起来组成一个字符串。
```
<?php
$a = 'hello ';
$b = 'world';
$c = $a.$b;
echo $c;
?>
```
:-: ![](https://img.kancloud.cn/11/ed/11ed3bf60f23cabaab16de37a39ecacb_521x254.png)
##### 赋值运算符
| 赋值运算符 | 作用 |
| ---------- | ------------------------------ |
| = | 将右边的值赋值给左边的变量 |
| += | 将左边值加右边值再赋值给左边 |
| -= | 将左边值减右边值再赋值给左边 |
| *= | 将左边值乘右边值再赋值给左边 |
| /= | 将左边值除以右边值再赋值给左边 |
| .= | 将左边值连接右边值再赋值给左边 |
| %= | 将左边值取余右边值再赋值给左边 |
赋值运算符的含义
```
<?php
$a = 1;
$a+= 1;
echo $a;
?>
```
:-: ![](https://img.kancloud.cn/d8/4c/d84c8d7e1e57a35ccab0c745cc1dbf68_512x251.png)
##### 比较运算符
| 比较运算符 | 含义 | 比较运算符 | 含义 |
| ---------- | ---------- | ---------- | -------------------- |
| == | 是否相等 | >= | 是否大于等于 |
| != | 是否不等于 | <= | 是否小于等于 |
| > | 是否大于 | === | 是否全等(类型也相等) |
| < | 是否小于 | !== | 是否不全等 |
比较运算符的含义
```
<?php
$a = 1;
$b = 2;
if($a<$b){
echo '$a 小于 $b';
}else{
echo '$a 不小于 $b';
}
```
:-: ![](https://img.kancloud.cn/0b/32/0b32127c53a07ef545a124a08cea76b9_513x253.png)
##### 逻辑运算符
| 逻辑运算符 | 含义 | 逻辑运算符 | 含义 |
| ---------- | ------ | ---------- | ---------------- |
| && | 逻辑和 | ! | 逻辑否 |
| AND | 逻辑和 | NOT | 逻辑否 |
| \|\| | 逻辑或 | XOR | 逻辑异或(找不同) |
| OR | 逻辑或 | | |
逻辑运算符的含义
```
<?php
$a = 1;
$b = 2;
if($a == 1 && $a < $b){
echo '$a 等于 1,且$a 小于 $b';
}
?>
```
:-: ![](https://img.kancloud.cn/55/7e/557e88d752053281aae54aa1e7c2dbec_513x249.png)
##### 按位运算符
| 按位运算符 | 名称 | 含义 |
| ---------- | -------- | ---------------------------------------- |
| & | 按位和 | 对应位都为1,结果为1 |
| \| | 按位或 | 对应位有1,结果为1 |
| ^ | 按位异或 | 对应位不同,结果为1 |
| ~ | 按位取反 | 0改为1,1改为0 |
| << | 左移 | 将变量的二进制位向左移动N位,右边空0补齐 |
| >> | 右移 | 将变量的二进制位向右移动N位,左边空0补齐 |
```
<?php
$a = 6; //二进制码为0110
$b = 2; //二进制码为0010
echo ($a & $b) . '<br>';
echo ($a | $b) . '<br>';
echo ($a ^ $b) . '<br>';
?>
```
:-: ![](https://img.kancloud.cn/fa/3e/fa3e319d9dd6c91acf574a34bffcdf6c_509x253.png)
$a & $b = 0110 & 0010 = 0010 = 2
$a | $b = 0110 & 0010 = 0110 = 6
$a ^ $b = 0110 & 0010 = 0100 = 4
##### 否定控制运算符
用在`操作数`之前,判断数字真假。
| 否定控制运算符 | 含义 |
| -------------- | ------ |
| ! | 逻辑否 |
| ~ | 按位否 |
##### 错误控制运算符
`@`符用来屏蔽错误信息的生成。
```
<?php
$err = @(1 / 0); //利用@屏蔽除数为0的错误
?>
```
:-: ![](https://img.kancloud.cn/b4/8c/b48c1fbdaf201073174921e36666b7a9_514x245.png)
##### 三元运算符
在三个操作符之间,语法:
```
(expr1)? (expr2):(expr3);
```
作用:如果expr1成立,执行expr2,否则执行expr3。
```
<?php
echo (1>2)? 1 :0;
?>
```
:-: ![](https://img.kancloud.cn/9f/f4/9ff4af8dda419b13d0d94a5948265879_517x257.png)
##### 运算符规则
- 加减乘除遵从数学原则
- 先括号内再括号外
- 赋值由右向左
#### 15.7 PHP函数
PHP函数分为`内置函数`和`自定义函数`。内置函数是PHP内部实现的函数。自定义函数是开发者可以自行定义功能的函数。
##### 内置函数
PHP提供了大量的内置函数供程序员直接使用,常见的包括数学函数、字符串函数、数组函数等。
```
<?php
$num = rand(1000,9999);
echo $num;
?>
```
rand函数是随机数字,可以指定随机数字的范围。上面的例子指定随机数从1000到9999。
:-: ![](https://img.kancloud.cn/6a/f5/6af54a946ec3ca5141b252bf4f2bebb0_521x252.png)
##### 自定义函数
语法:
```
function function_name(param1,param2,...)
{
code
}
```
function_name 是函数名,param1、param2是参数。
返回一个数字相加总和的自定义函数例子:
```
<?php
function numTotal($num1,$num2)
{
return $num1 + $num2;
}
echo numTotal(1,2);
?>
```
:-: ![](https://img.kancloud.cn/0e/99/0e99aed818155246b00759e9846470a0_520x256.png)
`return`指定函数返回值。函数是封闭的程序,所以通过预定义的参数位置传递参数,上面的$num1和$num2就是定义了两个参数。调用numTotal函数时将1给到$num1,将2给到$num2,就是参数的数据传递。
##### 对参数传递引用
```
<?php
$a = 1;
function echoNum(&$num) //这里定义函数的参数是传递的变量的引用,也就是这个变量的地址空间
{
echo $num;
}
echoNum($a);
?>
```
:-: ![](https://img.kancloud.cn/18/5b/185b06473cdedf8fa0c50999de4c54fc_513x253.png)
这种情况下,这个地址空间里的值不销毁,引用的值就一定是这个地址空间的值。上面的$a在这段地址空间的值为1,则函数调用时参数是引用这个$a的地址空间的值,所以最终输出为1。
##### 对函数的引用
对函数的引用,实际上是对函数返回值的引用。
```
<?php
function &expl($a = 1)
{
return $a;
}
$b = &expl('这是一个函数引用,这里函数返回值的空间是一定的');
echo $b;
?>
```
:-: ![](https://img.kancloud.cn/35/05/35056e75ab0746715f0784c89df5ded6_515x255.png)
对比以下非引用
```
<?php
function expl($a = 1)
{
return $a;
}
$b = expl('这里的返回值重新进入了$b开辟的内存空间');
echo $b . '<br>';
$a = expl('这里的返回值重新进入了$a开辟的内存空间');
echo $a . '<br>';
echo $b;
?>
```
:-: ![](https://img.kancloud.cn/80/39/8039284afa20d974df90c0c163ea14dd_521x264.png)
##### 对函数引用取消
对函数的引用就是对函数返回值的引用,所以对函数引用的取消就是对函数返回值的引用的取消。也就是断开变量名和变量内容的关系(断开变量名与内存空间值的关系)。使用unset()函数,但是unset()函数只是断开关系,并没有回收变量内容,也就是没有回收内存空间里面的值。
```
<?php
$a = 1;
$num = $a;
unset($num);
echo $a;
echo $num;
```
:-: ![](https://img.kancloud.cn/fc/e4/fce4fd87ccba2f8c40d45569eb9c441f_521x255.png)
这里的$num已经与内存空间中值1的关系已经被unset()断开。所以再使用$num变量会提示$num函数未定义。
#### 包含文件
包含文件通过require()和include()语句。
1. require():在脚本执行前读入包含的文件,读取错误时抛出致命错误,并停止脚本运行。
2. include():在指定到语句时读入包含的文件,读取错误时产生一个警告,并继续执行脚本。
通过require_once()或者include_once()语句作用是一样的,但只加载一次文件,防止变量重新赋值或函数重定义问题。
#### 15.8 流程控制
##### if 语句
```
if(条件判断){
执行语句;
}
```
##### if else 语句
```
if(条件判断){
执行语句A;
}else{
执行语句B;
}
```
##### elseif 语句
```
if(条件判断1){
执行语句A;
}elseif(条件判断2){
执行语句B;
}else{
执行语句C;
}
```
##### switch 语句
```
switch (条件判断语句){
case 判断结果A:
执行语句;
break;
case 判断结果B:
执行语句;
break;
case 判断结果C;
执行语句;
break;
default:
默认执行语句;
}
```
例子:
```
<?php
$a = 3;
switch($a){
case 1:
echo 1;
break;
case 2:
echo 2;
break;
default:
echo '其他数字';
}
?>
```
:-: ![](https://img.kancloud.cn/ff/0d/ff0d117731382d9989071c9acd041a91_518x252.png)
##### 循环语句
##### while 循环语句
```
while(判断条件){
执行语句;
}
```
##### do while 语句
do while 语句会执行至少会执行一次。
```\
do{
执行语句;
}while(判断条件)
```
##### for 循环语句
```
for(expr1;expr2;expr3)
{
执行语句
}
```
```
<?php
for($i = 0; $i<5;$i++){
echo 1 . "<br>";
}
?>
```
:-: ![](https://img.kancloud.cn/f5/06/f5063d09f7135139c77f479f9407d3f9_512x255.png)
这里$i初始化为0,每次循环自增1,$i小于5。
##### foreach 循环语句
foreach 语句是常用的一种循环,经常用来遍历数组。格式:
```
foreach(数组 as 数组元素){
对数组元素的执行语句;
}
```
可以根据数组的情况分成两种。
不包含键的:
```
foreach(数组 as 数组元素值){
对数组元素的执行语句;
}
```
包含键的:
```
foreach(数组 as 数组元素键=>数组元素值){
对数组元素的执行语句;
}
```
##### 使用break/continue跳出循环
在循环里可以使用break跳出整个循环。
在循环里可以使用continue跳出此次循环。
```
<?php
for($i=0;$i<5;$i++){
if($i==3){
continue;
}
echo $i . "<br>";
}
?>
```
:-: ![](https://img.kancloud.cn/9f/66/9f6612d63ba12a4660efd1f68d8020ff_517x250.png)
此次for循环里,当$i == 3时候,跳过了此次循环。
#### 15.9 字符串
##### 双引号和单引号的区别
- 双引号会解析字符串的值。单引号会直接显示变量名称。
- 双引号可以通过`\`转义符输出特殊字符,例如\n换行、\tTab、\\反斜杠等。
单引号只能通过`\`转义符输出\\'单引号本身、\\\反斜杠本身。
##### 字符串连接符
`.`号可以连接两个字符串。
```
<?php
echo '你好, ' . '中国';
?>
```
##### 手动转义字符
手动转义字符是通过`\`反斜杠使一些特殊字符转义为普通字符。
##### 自动转义字符
通过PHP的内置函数addslashes()来完成自动转义。
##### 计算字符串的长度
使用strlen()函数。
```
<?php
$str = '这是一段字符串';
echo strlen($str);
?>
```
:-: ![](https://img.kancloud.cn/50/80/5080c2ae201700897971596b1366f18e_510x255.png)
这里没有指定字符集,所以一个汉字的长度是3。
##### 字符串单词统计
仅针对英文单词,使用str_word_count()函数实现。
##### 清理字符串中的空格
有时候不需要空格,就需要清理。使用ltrim()、rtrim()、trim()函数。ltrim()从左边清除字符串头部空格,rtrim()从右边清除字符串头部空格,trim()清除左右两边字符串头部空格。
##### 字符串切分和组合
使用explode()将字符串分成不同部分存入一个数组;使用implode()函数,将数组的元素按照一定的间隔标准组成一段字符串。
explode()例子:
```
<?php
$a = '1;2;3;4';
print_r(explode(';',$a));
?>
```
:-: ![](https://img.kancloud.cn/07/ca/07cabf256726d83fa6f707e039ed8806_540x259.png)
implode()例子:
```
<?php
$arr = array(
0=>1,
1=>2,
2=>3
);
echo implode(',',$arr);
?>
```
:-: ![](https://img.kancloud.cn/1a/6b/1a6b2585922505f19bda06e9241a151b_513x257.png)
##### 字符串截取
使用substr()截取非中文字符串,使用m_substr()截取中文字符串。语法
```
substr(目标字符串,起始位置,截取长度)
```
例子:
```
<?php
$str = '1234556';
echo substr($str,1,3);
?>
```
:-: ![](https://img.kancloud.cn/3d/b9/3db9fd0f17655062bd536b8848874c21_534x262.png)
##### 字符串替换
substr_replace()函数替换字符串文本。
```
substr_replace(目标字符串,替换字符串,起始位置,替换长度)
```
例子:
```
<?php
$str = '1234567890123456';
echo substr_replace($str,'****',2,6);
?>
```
:-: ![](https://img.kancloud.cn/c1/5f/c15fe1d8e024b9acb060f7fc669876c5_515x251.png)
##### 字符串查找
strstr()在一个字符串中查找另外一个字符串,并返回查找到的字符串位置到尾部的字符串。
strpos()查找一个字符串在另一个字符串中的位置。
```
<?php
$str = 'aabbcc我aabbcc';
echo strpos($str,'我');
?>
```
:-: ![](https://img.kancloud.cn/8e/5d/8e5d6fa604da0ff1d4938f4993c739f9_518x258.png)
##### 大小写转换
strtolower()函数将字符串转为小写,strtoupper()函数将字符串转为大写,ucfirst()将整个字符串首字母改为大写,ucwords()函数将整个字符串中以空格为分隔符的单词首字母大写。
#### 15.10 正则表达式
正则表达式是把文本或字符串按照一定规则表示的方法,常用于文本匹配。
主要包括:
1. 方括号[]
方括号内是要用来匹配的字符。
2. 连接符-
很多情况下不能逐个列出字符就需要用到连接符,比如0到9使用`0-9`、`A-Z`、`a-z。`
3. 点号字符.
代表所有字符和数字。
4. 限定符(+*?{n,m})
- `+`表示前面的字符至少有1个。
- `*`表示前面的字符有任意个。
- `?`表示前面的字符有0个或1个。
- `{n,m}`表示前面的字符最少有n个,最多有m个。
5. 行定位符(^和$)
确定字符串所有出现的位置。例如:^a,匹配a只能在字符串头部出现。
6. 排除符([^])
用在方括号内表示排除,例如`[^a-z]`表示除了a-z的其他所有字符。
7. 括号字符(())
将正则表达式分成不同的操作部分,一个括号为一个部分。
8. 选择字符(|)
选择字符表示"或"。例如:[ab|ac|ad]匹配ab或ac或ad
9. 转义字符(\\)与反斜线(\\)
例子:
```
<?php
$str = 'abc12345bcd';
$rule = '/[0-9]?/';
preg_match_all($rule,$str,$arr);
echo "<pre>";
print_r($arr);
?>
```
preg_match_all()函数匹配所有可能的结果,每一次匹配从上一次匹配成功的位置开始,$rule是匹配规则,$str是匹配的字符串,$arr是最后的匹配结果数组。
:-: ![](https://img.kancloud.cn/5a/bb/5abb248f18fc2f89c42cd785df971392_521x388.png)
```
<?php
$str = 'abc12345bcd';
$rule = '/[0-9]{5}/';
$str = preg_replace($rule,';',$str);
echo $str;
?>
```
preg_replace (正则表达式, 要替换成的字符串, 匹配的字符串, 最大替换次数【默认-1,无数次】, 替换次数)。
:-: ![](https://img.kancloud.cn/45/d1/45d13cd370f514fded26c290c5a75678_519x259.png)
#### 15.11 PHP数组
数组是用来存储一系列值的结构。数组中的每个数值称为数据元素,每个数据元素对应一个表示称作`键`。
##### 数组的类型
##### 数字索引数组
数字索引数组是键为数字的数组,也就是一个数字键key对应一个数值value,key=>value。可以分别定义键和值,键不可重复。
```
$arr = array(0=>'张三',1=>'李四',2=>'赵五',5=>'王七');
```
也可以不指定键,则键从0自动递增。
```
$arr = array('张三','李四','赵五','王七');
```
##### 关联索引数组
关联索引数组是键不为数字的,其键可以是字符串。PHP底层运行时隐性地为其数组元素添加了数字索引。
```
$arr = array(''张家'=>'张三','李家'=>'李四','赵家'=>'赵五','王家'=>'王七');
```
##### 数组常量
使用const定义数组常量。
```
<?php
const arr = array('张三','李四','赵五','王七');
echo arr[2];
?>
```
:-: ![](https://img.kancloud.cn/b1/71/b171551ed794b4ddf26b8e1eac68a6d7_514x211.png)
也可以使用define()定义常量数组。
```
<?php
define('ARR',['张三','李四','赵五','王七']);
echo ARR[2];
?>
```
:-: ![](https://img.kancloud.cn/14/65/14651dbdb1fbe2f0d22a11b98eb6564b_520x216.png)
##### 数组结构
##### 一维数组
一维数组的每个数组元素是一个独立的值。
```
$arr = array('张三','李四','赵五','王七');
```
##### 多维数组
```
<?php
$arr = array(
0=>['张三','李四','赵五','王七'],
1=>['空调','洗衣机','电视机'],
2=>['1000','2000','3000'],
);
echo "<pre>";
print_r($arr);
?>
```
:-: ![](https://img.kancloud.cn/0e/5f/0e5fefa11911bd1e32c9d4ae52c3fc12_515x458.png)
##### 遍历数组
使用for循环、while循环、foreach循环可以遍历数组。其中foreach循环遍历数组速度最快,因为PHP底层为数组设计了迭代器和相关寻址指针能够快速查找到下一个元素值的地址空间。
遍历一维数组:
```
<?php
$arr = ['张三','李四','赵五','王七'];
for($i=0;$i<count($arr);$i++){
echo $arr[$i] . "<br>";
}
?>
```
:-: ![](https://img.kancloud.cn/0c/88/0c88c2d94b319cd30652a6d1fa3acad1_510x197.png)
```
<?php
$arr = ['张三','李四','赵五','王七'];
foreach($arr as $key => $value){
echo 'key = ' . $key . 'value = ' . $value . '<br>';
}
?>
```
:-: ![](https://img.kancloud.cn/0b/3b/0b3b359dee52fbc6f9637c10c9319a68_552x203.png)
遍历多维数组:
```
<?php
$arr = array(
0=>['张三','李四','赵五','王七'],
1=>['空调','洗衣机','电视机'],
2=>['1000','2000','3000'],
);
for($i=0;$i<count($arr);$i++){
foreach($arr[$i] as $value){
echo $value . '<br>';
}
}
?>
```
:-: ![](https://img.kancloud.cn/22/4c/224cdd2c1a05b39ed300c906513184fe_520x323.png)
##### 数组排序
简单的一维数组可以通过sort()、asort()、ksort()、rsort()、krsort()等函数进行排序,这些函数在PHP底层是由C函数zend_sort()实现的,它会判断在何时使用快排或者插入排序等算法。
当然,除了以上函数也可以自定义个PHP的快排或者插入排序等算法进行数组排序。
使用sort()函数排序:
```
<?php
$arr = [11,9,29,2,41,213];
sort($arr);
echo "<pre>";
print_r($arr);
?>
```
:-: ![](https://img.kancloud.cn/7e/5a/7e5a343a52e02b13ff30134416351d7f_523x261.png)
自定义排序:
```
<?php
$arr = [11,9,29,2,41,213];
for($i=1;$i<count($arr);$i++){
if($arr[$i] < $arr[$i-1]){
$a = $arr[$i-1];
$arr[$i-1] = $arr[$i];
$arr[$i] = $a;
}
}
echo "<pre>";
print_r($arr);
?>
```
这是一种简单的冒泡排序。时间复杂度是O(n²)。
:-: ![](https://img.kancloud.cn/7e/5a/7e5a343a52e02b13ff30134416351d7f_523x261.png)
##### 字符串和数组的转换
使用explode()将字符串切分成数组;使用implode()将字符串组成数组。
##### 向数组添加删除元素
使用push、pop、shift、unshift函数实现。
##### 添加数组元素
array_unshift()向数组头部添加元素:
```
<?php
$arr = [1,2,3,5];
array_unshift($arr,22,3,1);
echo "<pre>";
print_r($arr);
?>
```
:-: ![](https://img.kancloud.cn/a6/58/a6588c661cd338543919ce166f9cc94f_521x268.png)
array_push()向数组尾部添加元素:
```
<?php
$arr = [1,2,3,5];
array_push($arr,22,3,1);
echo "<pre>";
print_r($arr);
?>
```
:-: ![](https://img.kancloud.cn/a8/71/a871e27188c7b47436563b8659cefbfd_518x267.png)
array_shift()把数组头部元素删除:
```
<?php
$arr = [1,2,3,5];
array_shift($arr);
echo "<pre>";
print_r($arr);
?>
```
:-: ![](https://img.kancloud.cn/8f/01/8f0116001b34a2b6a76cbf63aa921e05_515x272.png)
array_pop()把数组尾部元素删除:
```
<?php
$arr = [1,2,3,5];
array_pop($arr);
echo "<pre>";
print_r($arr);
?>
```
:-: ![](https://img.kancloud.cn/0d/28/0d285a8845c3e66fc3e88b30db750358_523x215.png)
##### 统计元素个数
使用count()函数统计元素个数。语法:
```
count(expr1,[1]);
```
第二个参数设为1时表示统计所有元素,包括多维数组内的所有数组元素个数。
```
<?php
$arr = [1,1,2,2,3,45,1,];
echo count($arr);
?>
```
:-: ![](https://img.kancloud.cn/0f/87/0f879380cc760fb6e31cb902f7fc4474_518x219.png)
##### 去掉元素值相同(删除重复元素)
使用array_unique()函数。以元素值为准返回元素值具有唯一性的数组。
```
<?php
$arr = [1,1,1,2,3,4,5];
echo "<pre>";
print_r(array_unique($arr));
?>
```
:-: ![](https://img.kancloud.cn/b8/ee/b8ee2f2af2719a40f49cd8ffd2219ab4_523x240.png)
##### 调换数组的键和值
使用array_flip()函数。
```
<?php
$arr = [1=>'王',2=>'李','3'=>'赵'];
echo '<pre>';
print_r(array_flip($arr));
?>
```
:-: ![](https://img.kancloud.cn/c5/0a/c50ab257aa39388f86d785f25ab8a7be_524x243.png)
##### 序列化数组
serialize()函数将数组序列化为字符串,unserialize()函数则是其反序列化为数组。
##### 合并数组
使用array_merge()函数将两个数组组合成一个数组。
#### 15.12 时间和日期
##### 系统时区设置
1. 在php.ini文件设置。"date.timezone="选项设置时区。
2. 在引用程序中使用date_default_timezone_set()设置时区。
##### 获取当前时间戳
使用time()函数获得当前时间戳。
##### 获取当前日期和时间
使用date()函数。date()函数有很多种使用方法。
```
<?php
echo date('Y-m-d h:m:s',time()) ."<br>";
echo date('Y-m h:m',time()) ."<br>";
echo date('Y h:m:s',time()) ."<br>";
echo date('Y-m h',time()) ."<br>";
?>
```
:-: ![](https://img.kancloud.cn/ee/2b/ee2b6005594dc0312f358c0cccdb2caf_525x241.png)
##### 将时间转换为时间戳
strtotime()将时间转换成时间戳。
```
<?php
$t = '2018-11-11 02:23:01';
echo strtotime($t);
?>
```
:-: ![](https://img.kancloud.cn/b0/f7/b0f7a9b4b2aa42e87b0c583dfff36c3f_526x239.png)
##### 获得详细的时间信息
getdate()函数返回一个数组,包含日期和时间的各个部分。如果它的参数为空,则返回当前时间戳。
```
<?php
$t = "2018:1:1 23:01:02";
$st = strtotime($t);
$tp = getdate($st);
echo "年是".$tp['year'] . '<br>';
echo "月是".$tp['mon'] . '<br>';
echo "日是".$tp['mday'] . '<br>';
?>
```
:-: ![](https://img.kancloud.cn/01/fb/01fbb2c75ca8707beaf531723100d91b_518x240.png)
##### 校验日期
使用checkdate()函数进行日期校验。语法:
```
cheackdate(月份,日期,年份)
```
```
<?php
if(checkdate(13,31,2011))
{
echo '日期是合法的';
}else{
echo '日期不合法';
}
```
:-: ![](https://img.kancloud.cn/ab/16/ab161f1f7c228e74caa2ec811505965e_519x237.png)
##### 输出格式化时间戳的日期和时间
使用strftime()函数。格式:
```
strftime(格式,时间戳)
```
```
<?php
date_default_timezone_set("PRC");
echo (strftime("%b %d %Y %X",mktime(20,0,0,11,3,95)));
?>
```
:-: ![](https://img.kancloud.cn/21/06/210672d3b10569a240def967975801be_519x242.png)
##### 将日期和时间解析成时间戳
使用mktime()函数。语法:
```
mktime(小时,分钟,秒,月份,日期,年份)
```
```
<?php
echo mktime(1,2,0,10,2,98);
?>
```
:-: ![](https://img.kancloud.cn/1b/85/1b859fc6d80e257282c847840343f6a1_511x236.png)
#### 15.13 面向对象编程
所有的事务都看作一种`类`。一类生物,一类物品,一类车,一类楼房......
对象则是由这个类具象化产生的`实体`。
面向对象有三大特点:
1. 封装性。开发人员不必知道类的实现过程,只需要知道如何使用类,从而提高研发效率。
2. 继承性。A类继承B类,则A类是B类的子类。继承可以使子类具有父类允许传递的方法和属性。也可以重写相关方法或者属性。
3. 多态性。不同的类的对象收到相同的信息或不同的信息时,得到不同的结果。
##### 命名空间 namespace
命名空间namespace是用来封装各个项目的方法。常用在命名类、命名函数、命名常量名上。避免代码冲突和管理命名空间下的类、函数、常量名、变量名。
```
<?php
namespace /controller/system/data;
function addNum($a,$b)
{
echo $a + $b;
}
?>
```
这里的addNum函数在命名空间`/controller/system/data`下。
##### 声明类
PHP使用class关键字定义类。
```
<?php
namespace /controller;
public class person
{
}
```
修饰符可以对类、属性、方法进行修饰:
- public:默认,意味着被修饰的方法或属性可以从类外部访问。
- protected:受保护的,意味着被修饰的方法或属性只能从类的内部访问,通过继承的子类同样可以访问。
- private:私有的,意味着被修饰的方法或属性只能从类的内部访问,继承的子类也无法访问。
例子:
```
<?php
namespace /controller; //处于controller的命名空间
class person
{
public $name; //名字是共有的,可以从外部访问
protected $age; //年龄是受保护的,只有自己和自己的孩子可以访问
private $weight; //体重最私密,不让别人访问,只让自己可以访问
public function printName($n){
echo $n;
}
private function printWeight($w)
{
echo $w;
}
protected function printAge($a)
{
echo $a;
}
}
```
人是一个类。我们为人设置了姓名、年龄、体重的属性,并为人这个类设置行为方法。
##### 类的实例(对象)
面向对象的思想是一切皆为对象。类是对一类事物的抽象,对象是具体这类中具体的那个。所以要将类实例化为对象。则对象就是类的实例化。使用new对类实例化。
```
<?php
namespace controller;
class person
{
public $name = '未命名';
protected $age;
private $weight;
public function printName(){
echo $this->name . '<br>';
}
private function printWeight()
{
echo $this->weight;
}
protected function printAge()
{
echo $this->age;
}
public function setName($name)
{
$this->name = $name;
}
}
$a = new person;
$b = new person;
$a->printName();
$b->printName();
$a->setName('小李');
$a->printName();
$b->setName('小王');
$b->printName();
```
这里实例化了两个person类的对象,分别赋给变量$a(名字设置为小李)、$b(名字设置为小王)。
:-: ![](https://img.kancloud.cn/9a/72/9a729f2c21462157524b06e6ce631429_522x239.png)
##### 访问类的成员属性和方法
##### $this
`$this`存在于类的每一个成员的方法里,指向的是本实例。
```
<?php
namespace controller;
class person
{
public $name = '未命名';
protected $age;
private $weight;
public function printName(){
echo $this->name . '<br>';
}
}
$a = new person;
$a->printName();
```
:-: ![](https://img.kancloud.cn/6e/ea/6eea145b9d6c3fa6104661388b083527_512x243.png)
##### 操作符 ::
`::`符号可以在没有任何声明实例的情况下访问类中的静态属性和静态方法。语法:
```
关键字::变量名/常量名/方法名
```
关键字有:
- parent:表示可以调用父类的成员变量、常量和方法。
- self:表示可以调用当前类中的常量和静态成员变量。
- 类名:表示可以调用此类的常量变量和方法。
```
<?php
namespace controller;
class person
{
static $name = '未命名';
protected $age;
private $weight;
public function printName(){
echo self::$name . '<br>';
}
}
$a = new person;
$a->printName();
```
这里的$name成员属性设置为静态成员。则使用self关键字可以直接调用。
##### 构造方法和析构方法
构造方法是可选的,一个类只能声明一个构造方法。在实例化对象时会自动执行此对象的构造方法。PHP7的构造方法使用`__construct`定义。
```
<?php
namespace controller;
class person
{
static $name = '未命名';
protected $age;
private $weight;
function __construct()
{
echo '实例化时会自动执行构造方法';
}
public function printName(){
echo self::$name . '<br>';
}
}
$a = new person;
```
:-: ![](https://img.kancloud.cn/6b/8e/6b8ec4c925a4afb4f4c2670140c00524_531x243.png)
析构方法使用`__destruct`定义。在对象被销毁时候执行。PHP在请求结束后会释放所有资源,所以析构方法实际使用较少。
```
<?php
namespace controller;
class person
{
static $name = '未命名';
protected $age;
private $weight;
function __destruct()
{
echo '销毁对象时会自动执行构造方法';
}
public function printName(){
echo self::$name . '<br>';
}
}
$a = new person;
unset($a);
```
这里使用unset()销毁被实例化的对象触发了此对象的析构函数。
:-: ![](https://img.kancloud.cn/df/82/df82f2af44486afc365c7c7c38f55537_519x243.png)
##### 设置和访问属性
在任何时候类的属性被操作或访问都会触发访问方法`__set`和`__get`。面向对象OOP的思想不鼓励直接从类的外部访问类的属性。
```
<?php
namespace controller;
class person
{
static $name = '未命名';
}
$a = new person();
$a->age = 18; //这里触发__set
echo $a->age; //这里触发__get
```
:-: ![](https://img.kancloud.cn/96/5a/965adb3987f1126b00a5b8012c271f62_542x248.png)
##### 类的继承
类的继承使用`extends` 关键字。子类拥有父类具有的公共属性和公共方法。
```
<?php
namespace controller;
class person
{
public $name = '未命名';
private $age = 18;
public function getAge()
{
echo $this->age();
}
public function printName()
{
echo $this->name;
}
private function getMoney()
{
echo '我可以挣钱';
}
}
class son extends person
{
}
$a = new person;
$a->getAge(); //这里可以输出父类自己的私有属性$age
$s = new son;
$s->printName(); //可以输出父类公用的方法
$s->getAge; //这里无法输出父类的私有属性$age
```
:-: ![](https://img.kancloud.cn/fa/d5/fad5f3ae4ff6d2209f3a6657bdf6e950_534x289.png)
##### 静态方法和属性
使用`static`关键字可以定义静态属性和静态方法,可以实现不用实例化对象即可访问。静态属性不能通过已实例化对象访问(即静态属性不可由对象通过->操作符访问)。$this在静态方法中不可用,因为静态方法可以直接调用。
格式为:
```
类名::静态属性/静态方法
```
例子:
```
<?php
namespace controller;
class person
{
static $name = '未命名';
private $age = 18;
static public function getAge()
{
echo '这是静态方法';
}
}
echo person::$name;
echo "<br>";
person::getAge();
```
:-: ![](https://img.kancloud.cn/83/e4/83e43e117d96296fc5a8fe08232a71b6_521x297.png)
##### final 类和方法
`final`关键字是最终的意思。由final修饰的方法表示已经是最终方法无法被重写(子类无法重写该方法);由final修饰的类表示已经是最终的类无法被继承。
```
<?php
namespace controller;
class person
{
static $name = '未命名';
private $age = 18;
public final function getAge()
{
echo '这是静态方法';
}
}
class son extends person
{
public function getAge()
{
echo "尝试重写父类的getAge()方法";
}
}
$a = new person();
$a->getAge();
$s = new son();
$s->getAge();
?>
```
:-: ![](https://img.kancloud.cn/90/ef/90efb30d101d88ac91ff5f4fce948b4c_536x282.png)
提示无法重写父类的最终方法getAge()。
##### 抽象类
抽象类不能实例化,只能用来作为父类被继承。使用`abstract`关键字声明。抽象类的抽象方法也使用abstract关键字声明。
```
<?php
abstract class person
{
$name = '未定义';
abstract function getName();
abstract function setName();
}
```
##### 接口(接口类)
PHP只支持单继承,想使用多继承时就需要用到接口。接口不能声明变量,可以使用const声明常量成员,且接口的方法必须是抽象方法,所有的方法都必须是public访问权限。并且接口的方法在继承类必须实现所有方法。定义接口使用`interface`关键字。
```
<?php
interface person
{
public function getName();
public function setName();
}
```
继承接口的语法:
```
class 类名 implements 接口1,接口2,....{}
```
例子:
```
<?php
interface things
{
public function getName();
public function setName($name);
}
class person implements things
{
public $name = '未定义';
public function setName($name){
$this->name = $name;
}
public function getName(){
echo $this->name;
}
}
$a = new person;
$a->setName('小周');
$a->getName();
```
:-: ![](https://img.kancloud.cn/bf/12/bf127f2c2a46f9a0462b3a5ad15c7a74_512x273.png)
#### 15.14 异常和错误处理
PHP运行时会可能发生各种错误:来自语法的错误;程序员的编码错误;服务器或用户输出导致的错误等。
常见的错误和异常有哪些:
- 拼写错误
- 单引号双引号混用
- 括号使用混乱
- 缺少美元符号
- 调用不存在的变量与常量
- 调用不存在的文件
- 数据库服务器连接错误
........
##### 错误处理
##### php.ini 配置错误处理机制
| 名称 | 默认值 | 含义 |
| ---------------------- | ------ | ------------------------------------------------------------ |
| display_errors | On | 设置错误作为PHP输出的一部分。生产环境建议设置为Off |
| error_repoting | E_ALL | E_ALL会显示所有错误或者提示。设置为E_ALL & ~E_NOTICE只会显示错误和不良码。 |
| error_log | null | 设置错误日志 |
| html_errors | On | 错误日志是否采用HTML格式 |
| log_errors | Off | 是否将错误发送到主机服务器的日志文件 |
| display_startup_errors | Off | 是否显示PHP启动时的错误 |
| track_errors | Off | 是否保存最近一个警告或错误信息 |
##### 自定义错误和错误触发器
自定义错误处理函数,语法:
```
error_function(error_level,error_message,error_file,error_line,error_context)
```
参数含义:
| 参数 | 含义 |
| ------------- | -------------------------------------------- |
| error_level | 必须。定义错误报告级别 |
| error_message | 必须。规定错误信息 |
| error_file | 可选。规定错误在其中发生的文件名 |
| error_line | 可选。规定错误发生的行号 |
| error_context | 可选。规定数组,包含发生错误时的每个变量及值 |
错误级别:
| 数值 | 常量 | 含义 |
| ---- | ------------------- | ------------------------------------------------------ |
| 2 | E_WARNING | 不致命的运行错误不停止脚本 |
| 8 | E_NOTICE | 运行通知,脚本发现可能有错误,但也可能在脚本运行时发生 |
| 256 | E_USER_ERROR | 致命的用户生成的错误 |
| 512 | E_USER_WARNING | 非致命的用户生成的错误 |
| 1024 | E_USER_NOTICE | 用户生成的通知 |
| 4096 | E_RECOVERABLE_ERROR | 可获得的致命错误,可被用户定义的处理程序捕获 |
| 8191 | E_ALL | 所有错误和警告 |
创建错误处理函数:
```
function getError($errorLevel,$errorMsg)
{
echo "错误:{errorLevel} , $errorMsg";
die();
}
```
创建错误处理程序后要使用set_error_handler()函数设置用户自定义的错误处理函数。用于创建运行时用户自己的错误处理方法。成功返回原来的错误处理程序,失败返回null。语法:
```
set_error_handler(error_function,error_type)
```
error_type为可选参数,不选择默认为E_ALL。
例子:
```
<?php
function getError($errorLevel,$errorMsg)
{
echo "错误:{$errorLevel} , $errorMsg";
die();
}
set_error_handler("getError");
echo $a;
?>
```
:-: ![](https://img.kancloud.cn/55/ef/55ef56a0669ab8b5e3aff284f76eb7b3_536x294.png)
trigger_error()函数创建用户自定义的错误消息。用于用户在自己指定的情况下触发错误。
```
<?php
$a = 10;
if($a<20){
trigger_error('This number must be greater than 20');
}
```
:-: ![](https://img.kancloud.cn/60/8f/608f3555fa1044d708e0811051ff4926_510x281.png)
set_error_handler()与trigger_error()组合使用:
```
<?php
function getError($errorLevel,$errorMsg)
{
echo "错误:{$errorLevel} , $errorMsg";
die();
}
set_error_handler("getError");
$num = 5;
if($num > 4){
trigger_error('This number has to be less than 4',E_USER_WARNING);
}
?>
```
:-: ![](https://img.kancloud.cn/1b/69/1b69b8ca3e416bf66258f73393ded356_521x278.png)
##### 异常处理
异常用于发生指定错误时改变脚本的运行流程。异常触发时,会发生以下动作:
- 当前代码状态被保存。
- 代码切到异常处理器函数。
- 根据情况处理器也许从保存的代码状态重新执行代码、终止脚本、从其他位置继续执行脚本。
抛出异常时,没有catch块捕获异常或没有set_exception_handler()函数做处理,会发生严重错误。
##### 异常的基本处理
异常处理语法:
```
try{
throw new Exception('触发异常');//抛出异常,应定义抛出的条件
}catch(Exception $e){
echo '这里是捕获异常后运行的代码'; //catch块捕获异常并在捕获后运行其代码
}
```
值得注意的是:PHP只能手动使用throw抛出异常。且一个throw必须对应一个catch块。注意**可以多个try catch块嵌套try catch块。**
```
<?php
try{
$num = 10;
if($num < 20){
throw new Exception('$num 不能小于20');
}
}catch(Exception $e){
echo $e->getMessage();
echo "已捕获异常";
}
```
:-: ![](https://img.kancloud.cn/41/23/4123c9b5377ea33b5023a1a6f6107729_515x229.png)
##### 自定义异常处理器
自定义的异常处理器必须继承Exception 类,可以看作是其的扩展。
```
<?php
class numException extends Exception{
public function errMessage()
{
$msg = $this->getLine().'行,位于文件:'.$this->getFile().'错误信息:'.$this->getMessage();
return $msg;
}
}
try{
$num = 10;
if($num < 20){
throw new numException('这个数字不能小于20');
}
}catch(numException $e){
echo $e->errMessage();
}
```
:-: ![](https://img.kancloud.cn/be/0e/be0e2f30235534bb36a1cc00900c179a_548x242.png)
##### 处理多个异常
```
<?php
class numException extends Exception{
public function errMessage()
{
$msg = $this->getLine().'行,位于文件:'.$this->getFile().'错误信息:'.$this->getMessage();
return $msg;
}
}
try{
$num = 10;
if($num < 20){
throw new numException('这个数字不能小于20');
}
if(0<1){
throw new Exception('这是抛出一个普通的异常');
}
}catch(numException $e){
echo $e->errMessage();
}catch(Exception $e){
echo '捕获到异常';
}
```
##### 设置顶层的异常处理函数
所有未捕获的异常都可以通过顶层的异常处理器来处理。使用set_exception_handler()函数来设置。语法:
```
set_exception_handler(exception_function)
```
```
<?php
function exceptionHand($exception)
{
echo '发生异常:' . $exception->getMessage();
}
set_exception_handler('exceptionHand');
throw new Exception('发生一个异常');
```
:-: ![](https://img.kancloud.cn/98/26/982668d8edfd1769e942e029037610c8_526x225.png)
#### 15.15 PHP与页面交互
##### 表单
PHP与页面交互一般通过页面表单提交信息,PHP接收信息进行处理。表单提供以下功能分类:
- 文本框
- 单选框
- 复选框
- 下拉列表
- 隐藏表单
- 重置按钮
- 提交按钮
##### 传递数据的方法
表单传递数据或者平时的HTTP数据传递数据的方法一般为POST或者GET。
POST 传递数据不会限制数据和变量大小限制,且不会以URL方式呈现出来。
GET传递数据不能超过100字节,且显性地呈现在URL上。
##### PHP获取表单提交数据
$_POST[]全局变量获得POST提交的数据。
$_GET[]全局变量获得GET提交的数据。
```
<html>
<body>
<form action='test.php' method='post'>
<input type='text' name='name' size='10'>
<input type='checkbox' name='acolor' value='red'>
<input type='checkbox' name='bcolor' value='blue'>
<input type='checkbox' name='ccolor' value='black'>
<input type='radio' name='aredio' value='1'>
<input type='radio' name='aredio' value='2'>
<input type='radio' name='aredio' value='3'>
<select name='aselect' size='1'>
<option value='xinjiang'>新疆</option>
<option value='hainan'>海南</option>
<option value='sichuan'>四川</option>
<option value='chongqing'>重庆</option>
</body>
</html>
```
test.php
```
<?php
print_r($_POST);
print_r($_POST['aradio']);
print_r($_POST['aselect']);
print_r($_POST['name']);
```
以上方法通过$_POST全局变量获得表单通过POST方法提交的数据。
##### PHP对URL传递的参数进行编码
如果需要对URL传递的参数进行加密使用urlencode()和 rawurlencode()函数。其反操作解密函数使用urldecode()和rawurldecode()函数。
```
<?php
$str = '这一一段 未加密的段落';
$line1 = 'index.php?str=' . urlencode($str);
$line2 = 'index.php?str=' . rawurlencode($str);
echo $line1 . '<br>';
echo $line2 . '<br>';
echo urldecode($line1) .'<br>';
echo urldecode($line2) .'<br>';
echo rawurldecode($line2);
?>
```
:-: ![](https://img.kancloud.cn/31/3e/313e82144410b892ef5bd4e79d0090cc_516x283.png)
#### 15.16 PHP操作MySQL
##### 准备工作
首先打开php.ini,找到`;extension=mysqli`,去掉前面的`;`号。保存php.ini文件。
:-: ![](https://img.kancloud.cn/0b/85/0b85c83f282f582ee43c625f604d1b39_539x212.png)
##### 使用mysqli_connect()连接MySQL服务器
```
mysqli_connect('MySQL服务器地址','用户名','用户密码','需要连接的数据库','[端口号默认3306]');
```
##### 使用mysqli_select_db()函数改变默认的数据库
```
mysqli_select_db(连接对象,'更改后的数据库')
```
```
<?php
$db = mysqli_connect('localhost','root','123456','test1');
mysqli_select_db($db,'test2');//将$db连接对象的数据库更改为test2
```
##### 使用mysqli_close()函数关闭MySQL连接
```
mysqli_close(数据库连接对象)
```
##### 使用mysqli_query()函数执行SQL语句
```
mysqli_query(数据库连接对象,SQL语句)
```
```
<?php
$db = mysqli_connect('localhost','root','123456','test1');
$sq = 'select * from student';
$result = mysqli_query($db,$sq);
if($result){
echo '查询成功';
}else{
echo '查询失败';
}
?>
```
##### 获取查询结果的记录集
使用mysqli_num_rows()函数获取查询结果条数。只对select语句有效。
```
mysqli_num_rows(result)
```
使用mysqli_affected_rows()函数获取查询、插入、更新、删除操作影响的行数。connection表示上一次操作的连接对象。返回结果为-1表示错误。返回其他包括0的正整数表示上次操作影响的行数。
```
mysqli_affected_rows(connection)
```
##### 取出查询结果
使用mysqli_fetch_rows()函数取出查询结果集。再使用循环获得每条数据的每一列具体数据。
```
mysqli_fetch_rows(result)
```
```
<?php
$db = mysqli_connect('localhost','root','123456','test1');
$sq = 'select * from student';
$result = mysqli_query($db,$sq);
while($row = mysqli_fetch_rows($result)){
echo $row[0]; //输出本条数据的第1列
echo $row[1]; //输出本条数据的第2列
echo $row[2]; //输出本条数据的第3列
echo $row[3]; //输出本条数据的第4列
}
?>
```
##### 获取结果集中的记录作为对象
使用mysqli_fetch_object()函数。
```
<?php
$db = mysqli_connect('localhost','root','123456','test1');
$sq = 'select * from student';
$result = mysqli_query($db,$sq);
while($row = mysqli_fetch_object($result)){
echo $row->id;
echo $row->name;
echo $row->age;
echo $row->num;
}
?>
```
##### 使用mysqli_fetch_array()函数获取结果集记录
```
mysqli_fetch_array(result,[resuilt_type])
```
resuilt_type有两种常量参数:MYSQL_ASSOC表示关联数组,MYSQL_NUM表示数字数组,MYSQL_BOTH二者兼有(默认)
```
<?php
$db = mysqli_connect('localhost','root','123456','test1');
$sq = 'select * from student';
$result = mysqli_query($db,$sq);
while($row = mysqli_fetch_array($result)){
echo $row['id'];
echo $row['name'];
echo $row['age'];
echo $row['num'];
}
?>
```
##### 使用mysqli_free_result()函数释放资源
```
mysqli_free_result(SQL请求返回的结果对象)
```
通过mysqli_free_result($result)使用SQL请求返回的结果对象$result占用的资源。
#### 15.17 PDO数据库抽象类库
PDO扩展是PHP访问数据库定义的一个轻量级,一致性的接口,提供了一个数据库访问抽象层。PHP可以使用MySQL函数操作MySQL,可以使用其他函数操作Oracle等其他函数,这样会增加PHP程序在处理数据库方面的难度和工作量,减少了其灵活性。PDO就是解决这样问题的"数据库抽象层"。
经测试,PDO操作MySQL比直接用PHP操作MySQL效率高。PDO扩展类是C语言编写并编译进PHP的,有兴趣可以查看源码学习。
##### 准备工作
PDO类库是PHP自带的类库,在php.ini中把带有php_mysql的分号去掉。如果要启用Oracle数据库,可以启用pdo_oci。
:-: ![](https://img.kancloud.cn/6b/9b/6b9bcc06a5bd32b21ddc6f42a12dcc14_404x108.png)
##### 使用PDO操作MySQL
```
PDO::__constuct(DNS,username,password,driver_options)
```
DNS是数据源,username是用户名,password是用户密码,driver_options是其他参数。
DNS是一个字符串,写法:
```
'数据库服务器类型:host=数据库地址;dbname=数据库名称'
```
driver_options参数有多种作用,有兴趣的同学可以自行学习。
##### 连接MySQL
```
<?php
$db = new PDO('mysql:host=localhost;dbname=test1','root','123456');
?>
```
##### 使用try catch
PDOException 继承了Exception基础异常类,可以使用它获得PDO连接数据库时候的相关错误信息。
```
<?php
try{
$db = new PDO('mysql:host=localhost;dbname=test1','root','123456');
}catch(PDOException $e){
echo '连接错误:'.$e->getMessage();
}
?>
```
获得SQL请求执行时候的错误:
```
<?php
try{
$db = new PDO('mysql:host=localhost;dbname=test1','root','123456');
}catch(PDOException $e){
echo '连接错误:'.$e->getMessage();
}
$sqlQuery = 'select * from student';
$db->exec($sqlQuery);
echo $db->errorCode();//获取执行时的错误码
print_r($db->errorInfo());//获取执行时错误的信息
?>
```
##### 通过foreach 遍历PDO查询结果对象
使用PDO查询数据时一定要使用query()方法。其他操作使用exec()方法。
```
<?php
try{
$db = new PDO('mysql:host=localhost;dbname=test1','root','123456');
}catch(PDOException $e){
echo '连接错误:'.$e->getMessage();
}
$sqlQuery = 'select * from student';
$result = $db->query($sqlQuery);
foreach($result as $row){
$name = $row['name'];
$id = $row['id'];
}
?>
```
##### 使用fetch()获取返回数据
使用fetch()可以获得一条返回结果的记录,使用fetchAll()可以获得返回的数据对象的所有记录。它们可以指定将返回结果读取为关联数组(PDO::FETCH_ASSOC)、数字索引数组(PDO::FETCH_NUM)、关联数组加数字索引数组(FETCH_BOTH)、对象(PDO::FETCH_OBJ)。
```
<?php
try{
$db = new PDO('mysql:host=localhost;dbname=test1','root','123456');
}catch(PDOException $e){
echo '连接错误:'.$e->getMessage();
}
$sqlQuery = 'select * from student';
$result = $db->query($sqlQuery);
foreach($row = $result->fetch(PDO::FETCH_ASSOC)){
$name = $row['name'];
$id = $row['id'];
}
echo 'total : ' $result->rowCount();//结果一共多少条
?>
```
```
<?php
try{
$db = new PDO('mysql:host=localhost;dbname=test1','root','123456');
}catch(PDOException $e){
echo '连接错误:'.$e->getMessage();
}
$sqlQuery = 'select * from student';
$result = $db->query($sqlQuery);
foreach($result->fetchAll){
$name = $row[0];//可以使用数字索引数组
$id = $row[1];
$text = $row['text'];//可以使用关联数组
}
echo 'total : ' $result->rowCount();//结果一共多少条
?>
```
##### 使用PDO执行添加修改语句
```
<?php
try{
$db = new PDO('mysql:host=localhost;dbname=test1','root','123456');
}catch(PDOException $e){
echo '连接错误:'.$e->getMessage();
}
$sqlQuery = "INSERT INTO user(id,name) VALUES(30,'小张')";
if($db->exec($sqlQuery)){
echo "添加成功";
}
?>
```
##### 使用PDO执行SQL的删除语句
```
<?php
try{
$db = new PDO('mysql:host=localhost;dbname=test1','root','123456');
}catch(PDOException $e){
echo '连接错误:'.$e->getMessage();
}
$sqlQuery = "DELETE FROM student WHERE name = '小张'";
if($db->exec($sqlQuery)){
echo "删除成功";
}
//上面可以使用try catch语句给程序添加容错方案
?>
```
#### 15.18 Smarty模板
Smarty是使用PHP写出来的模板引擎。它分离了内容和逻辑代码,可以将原来与HTML代码混写的PHP代码分离出来。许多框架内置或者改良Smarty模板的功能加入了其中。Smarty模板有在视图层进行逻辑运算、流程控制等功能。
##### MVC结构
MVC是指的是`模型`、`视图`、`控制器`。模型负责数据的组织结构,视图负责呈现用户界面,控制器负责流程的逻辑控制。
所以MVC结构就是把一个程序的输入、处理过程、输出分开。当请求来到时,'控制器'对请求做出反应,调用'模型'和'视图',将相关的代码和数据返回来满足用户需求。
##### Smarty安装配置
1. 首先在官网下载Smarty软件包。
2. 解压软件包到网站目录下。
3. 编辑php.ini文件,添加包含Smarty类库文件路径。`include_path='[Smarty类库文件路径]'`。
PHP和HTML混写例子:
```
<html>
<body>
<p>
<?php echo "这是HTML与PHP混写"; ?>
</p>
</body>
</html>
```
使用Smarty模板引擎分离视图和控制器例子:
index.php文件
```
<?php
require_once('Smarty.class.php');
$smarty = new Smarty;
$smarty->template_dir = '/data/wwwroot/demo/templates';
$smarty->config_dir = '/data/wwwroot/demo/config';
$smarty->cache_dir = '/data/wwwroot/demo/cache';
$smarty->compile_dir = '/data/wwwroot/demo/templates_c';
$smarty->assign('message','1');//渲染了message
$smarty->display('index.tpl');//渲染给了index.tpl模板文件
```
index.tpl文件
```
<html>
<body>
<p>message:{$message}</p>//这里将上面渲染的message参数展示出来
</body>
</html>
```
从上面可以看出来,Smarty模板引擎比起PHP和HTML混写,将视图层和控制器层分离开来。在实际开发环境中,模板引擎是非常重要的。
##### 流程控制
```
<html>
<body>
{if $message == '1'}<p>message:{$message}</p>//这里将上面渲染的message参数展示出来
{elseif $message == '2'}<p>message:2</p>
</body>
</html>
```