https://www.jianshu.com/p/708802f0f239
- 前言:php经历了php7.1~php7.4,终于2020年11月26日发布了php8.0.0,截止目前,最新一次的更新发布是2021年5月6号
接下来我们就来康康php8带来了哪些新特性呢?先看一下官方介绍
PHP 8.0 是 PHP 语言的一个主版本更新。
它包含了很多新功能与优化项, 包括命名参数、联合类型、注解、构造器属性提升、match 表达式、nullsafe 运算符、JIT,并改进了类型系统、错误处理、语法一致性。接下来我们安装一下php8,逐个的了解一下
下载页面 或者直接指向下载命令
zhangguofu@localhost Downloads $ wget https://www.php.net/distributions/php-8.0.6.tar.gztar -zxvf php-8.0.6.tar.gz
zhangguofu@localhost Downloads $ tar -zxvf php-8.0.6.tar.gz
zhangguofu@localhost Downloads $ cd php-8.0.6
zhangguofu@localhost php-8.0.6 $ sudo mkdir /usr/local/php8
# 修改权限
zhangguofu@localhost php-8.0.6 $ sudo chmod 777 /usr/local/php8
- 我是在mac下安装的,遇到了一个报错
configure: error: Please specify the install prefix of iconv with --with-iconv=
解决方法也很简单,看报错信息,让在configure的时候 指定iconv的目录,我看了一下,我的mac里面并没有安装,使用下面命令安装
zhangguofu@localhost php8 $ brew install libiconv
- 开始安装php8
如果遇到报错可以参考这篇文章
zhangguofu@localhost php-8.0.6 $ ./configure --prefix=/usr/local/php8/ --enable-debug --enable-fpm --with-config-file-path=/usr/local/php8/etc/ --with-iconv=/usr/local/opt/libiconv
zhangguofu@localhost php-8.0.6 $ make && make install
- 安装成功
zhangguofu@localhost bin $ pwd
/usr/local/php8/bin
zhangguofu@localhost bin $ /usr/local/php8/bin/php -v
PHP 8.0.6 (cli) (built: May 26 2021 14:43:31) ( NTS DEBUG )
Copyright (c) The PHP Group
Zend Engine v4.0.6, Copyright (c) Zend Technologies
zhangguofu@localhost bin $
#添加配置文件
zhangguofu@localhost php-8.0.6 $ cp php.ini-development /usr/local/php8/etc/php.ini
开始测试
- 至此,php8安装完成,为了方便演示,我选择在laravel里面的单元测试模块执行,当然,你直接使用 /path/php /path/demo.php 去执行php脚本也可以。如果你想这样执行,那下面配置这一步可以跳过
- 这里简单介绍一下 laravel里面怎么配置测试环境,我的一个文件在项目根目录/tests/Unit/Php8Test.php下面,方法名称 必须是test开头才可以执行测试
通过phpstorm面板设置
你可以为每个test类设置一个执行环境,interpreter,就是你的php解释器的路径
环境配置完毕
回头看看我们前面说的新特性
PHP 8.0 是 PHP 语言的一个主版本更新。
它包含了很多新功能与优化项, 包括命名参数、联合类型、注解、构造器属性提升、match 表达式、nullsafe 运算符、JIT,并改进了类型系统、错误处理、语法一致性。命名参数,如果一个函数里面有m个参数,但是你只想指定 第m-1 那一个参数,在php8里面是可以实现的,但是php7是报错的
但是注意两点:仅仅指定必填参数,跳过可选参数。
参数的顺序无关
person(age:100);
}
public function person($name="",$sex="",$age="")
{
echo "the name is $name,the sex is $sex,the age is $age".PHP_EOL;
}
}
$obj =new Eight_Php();
$obj->run();
- 构造器属性提升,这样我们就可以通过构造方法声明我们的成员属性,而不需要提前声明,从而减少我们的代码量
相关代码:
#php8
namespace Php8\Eight_Php;
class Eight_Php
{
public function __construct(public $name='')
{
}
public function run()
{
echo $this->name.PHP_EOL;
}
}
$obj =new Eight_Php("jimi");
$obj->run();
#php7
namespace Php8\Seven_Php;
class Seven_Php
{
public $name='';
public function __construct($name)
{
$this->name=$name;
}
public function run()
{
echo $this->name.PHP_EOL;
}
}
$obj=new Seven_Php('jimi');
$obj->run();
- 联合类型,你可以在声明变量的同时声明类型,在代码运行时会被校验,还是以刚才代码为例,我对name 声明int,如果是参数接收多种类型,比如,
float|string
表示接收 字符串和浮点型。感觉有点像强类型了吧,单其实也不是 float 和int 会自动转化,比如参数只接受int ,传值是1.23 类型转换后就是1
-
通过上一个例子其实也看出来了,php8增强了字符串和数字之间的校验
-
而且这种类型校验的增强,还体现在对内部函数的校验,提升了报错级别,如果内部函数的类型不对,原来的是报warning,现在是fatal
重点看一看JIT
PHP 8 的JIT(Just In Time)编译器将作为扩展集成到php 中Opcache 扩展 ,PHP 8 引入了两个即时编译引擎,一个是tracing jit ,一个是function jit,用于运行时将某些操作码直接转换为从cpu 指令。 这意味着使用JIT 后,Zend VM 不需要解释某些操作码,并且这些指令将直接作为CPU 级指令执行。
- 但是再了解jit之前,我们要知道为什么要出现jit,那么我们就要了解php到底是怎么运行的。那么我们从两个方面去看这个问题,一种是php-fpm(接收web请求),一种是php的CLI 解释器(使用php运行脚本)
什么是php-fpm
- 在了解php-fpm之前,请大家先思考一个问题,一个用户发起了一个web(niginx服务器)请求,在php代码里面,那么我们怎么样才可以通过 _GET,$_SERVER获取一些请求信息呢?我们应该参照什么格式去组装数据呢?
其实我们知道,每种动态语言,也就是解释性语言,都需要通过对应的解析器才能被服务器识别,但是解释器和服务器 必须遵循某种协议,双方才能够正常通信,那么这种协议就是CGI协议,但是CGI的机制是每响应一次web请求,都会创建和初始化一个新的处理进程,请求结束就kill掉这个进程。那每次请求,都要执行这三步 创建->初始化->结束,那其实这个过程不仅浪费了资源,而且效率也很低。那怎么办?FastCGI应时而生,作为CGI的改良版本,FastCGI会启动一个常驻服务进程,这个进程不需要管理生命周期,也就避免了进程的重复的创建和结束,另一方面,不需要再重复的读取环境变量,每当有web请求过来,由FastCGI管理器,也就那个常驻服务进程去启动CGI解释器进程
- 好了,既然有了CGI,那么针对这些解释性语言,比如php phython,都要根据自己的语言做一个适配吧。那么php官方就弄出来了PHP-CGI,php定制版的CGI。
- 但是随着使用,大家发现了PHP-CGI的问题
1.修改php.ini 后必须重启PHP-CGI才可以生效,而不能实现平滑重启
2.直接干掉PHP-CGI,php就不能运行了,这显然是不能接受的
3.这玩意不会自己管理进程,它只能解析请求,返回结果
那么FastCGI都已经到来了,php的FastCGI还会远吗,当然不会,到 2004年一个叫 Andrei Nigmatulin的屌丝发明了PHP-FPM,PHP-FMP 全名叫做PHP-FASTCGI Process Manager,说白了就是php定制版的FastCGI(这里强调一下,不管是PHP-CGI 还是 PHP-FPM都是为了实现CGI协议,而不是一种新的协议),其实有一句话刚才我没说,网上很多人说PHP-CGI 就是 php管理FAST-CGI的一种程序,那你现在知道了PHP-FMP 全名叫做PHP-FASTCGI Process Manager之后,你可以理直气壮的跟他们说no,并给他们普及一下这个知识点了。
php-fmp的进程包括 master(常驻服务程序)和worker进程两种
master进程
- master负责进程的调度(比如worker进程不够的时候去fork一个子进程)
- 负责监听端口,一般是9000这个端口,可以在配置文件里面设置,当然,还有另外一种方式,就是通过socket,可以通过
netstat -nap | grep master的进程号
查看端口信息(9000端口其实就是tcp的通信方式,而socket是说的unix socket,从效率上来说,unix socket显然是最好的,因为它是进程之间的通信,但是unix socket要保证是在一台服务器,如果是不同机器之间的通信,还是要使用tcp通信)
- 接收来自服务器的请求
work进度 看名字就知道了,就是真正的打工阶级,代码真正执行的地方
- 再来看看php-fmp和nignx是怎么通信的
以socker通信为栗子,nginx的conf文件里面,可以看到下面这段信息
location ~ [^/]\.php(/|$)
{
try_files $uri =404;
fastcgi_pass unix:/tmp/php-cgi.sock;
fastcgi_index index.php;
include fastcgi.conf;
}
相信这段信息大家都可以看明白,/tmp/php-cgi.sock 就是php和nginx联系的桥梁,同时我们也看到了include fastcgi.conf
,我们来看一下
root@6d05153a8988:/usr/local/nginx/conf# cat fastcgi.conf
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param REQUEST_SCHEME $scheme;
fastcgi_param HTTPS $https if_not_empty;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param REDIRECT_STATUS 200;
fastcgi_param PHP_ADMIN_VALUE "open_basedir=NULL";
我们看到了一些熟悉的,比如REMOTE_ADDR,REQUEST_URI,现在你应该明白了,我们通过$_SERVER获取到的信息就是这个配置文件里面指定的
我们再来看一下php-fmp的配置文件(请注意看里面的注释,我不做解释了)
root@6d05153a8988:/usr/local/php/etc# cat php-fpm.conf
[global]
pid = /usr/local/php/var/run/php-fpm.pid
error_log = /usr/local/php/var/log/php-fpm.log
log_level = notice
[www]
listen = /tmp/php-cgi.sock
listen.backlog = -1
listen.allowed_clients = 127.0.0.1
listen.owner = www
listen.group = www
listen.mode = 0666
user = www
group = www
# 如何控制子进程,选项有static和dynamic
#区别:
#如果dm设置为 static,那么其实只有pm.max_children这个参数生效。系统会开#启设置数量的php-fpm进程。
#如果dm设置为 dynamic,那么pm.max_children参数失效,后面3个参数生效。
#系统会在php-fpm运行开始 的时候启动pm.start_servers个php-fpm进程,
#然后根据系统的需求动态在pm.min_spare_servers和pm.max_spare_servers之#间调整php-fpm进程数。
pm = dynamic
# 静态方式下开启的php-fpm进程数量
pm.max_children = 20
# 动态方式下的起始php-fpm进程数量
pm.start_servers = 10
# 动态方式下的最小php-fpm进程数
pm.min_spare_servers = 10
# 动态方式下的最大php-fpm进程数量
pm.max_spare_servers = 20
# php-fpm子进程能处理的最大请求数
pm.max_requests = 1024
pm.process_idle_timeout = 10s
request_terminate_timeout = 100
request_slowlog_timeout = 0
slowlog = var/log/slow.log
- 关于php-fpm 的相关操作
INT, TERM
QUIT 平滑终止
USR1 重新打开日志文件
USR2 平滑重载所有worker进程并重新载入配置和二进制模块
启动: /usr/local/php/sbin/php-fpm
查看进程数: ps aux | grep -c php-fpm
查看mater进程号:ps aux|grep 'php-fpm: master'|grep -v grep|awk '{print $2}'
或者cat /usr/local/php/var/run/php-fpm.pid
# 强制关闭
pkill php-fpm
kill -INT `cat /usr/local/php/var/run/php-fpm.pid`
kill -INT [pid]
# 平滑重启 其实就是通过创建新的进程使 php.ini 生效
kill -USR2 `cat /usr/local/php/var/run/php-fpm.pid`
kill -USR2 [pid]
小结
至此,php-fpm 算是说完了,其实通过上面的解说,大家也会明白一个问题,为什么lnmp 承受的并发比lamp高,php-fpm 是不是其中的一个原因呢?
php的cli解释器
运行步骤
异同
【外卖连接】