[官方介绍地址](https://www.php.net/releases/8.0/zh.php)
php 8.0 五大更新重点
- 效能提升
- 语法扩充
- 弹性强类别
- 更加严谨
- 调节内套件与新增函数
性能测试图表
PHP 8.0 值得关注的改进
PHP 8.0 引入了 Just In Time (JIT) 编译器,能够进一步提高 PHP 脚本的执行速度。
PHP 8.0 合并了诸多性能优化
-
JSON 支持现在被视为语言的核心部分,始终可用,而不是作为可选模块。
@1.extension_loaded('json')
@2.function_exists('json_decode')
始终返回true 支持 named 参数,因为它们能够指定参数名称而不是其确切顺序。
支持类/属性/函数/方法/参数/常量的结构化元数据的属性(或在其他语言中也称为注释或修饰符)。
支持可以指示多种不同类型的联合类型,这些类型可以用作参数或函数的返回类型。
支持静态返回类型。
str_contains()函数是一种检查字符串是否包含在另一个字符串中的简便方法,而不必使用strpos等。与之相似的是新的str_starts_with()和str_ends_with()函数,这些函数很容易解释。
添加了Nullsafe运算符,作为在方法上应用空合并行为的快速简便的方法
什么是 JIT
1、动态编译(dynamic compilation)指的是“在运行时进行编译”;与之相对的是事前编译(ahead-of-time compilation,简称AOT),也叫静态编译(static compilation)。
2、JIT编译(just-in-time compilation)狭义来说是当某段代码即将第一次被执行时进行编译,因而叫“即时编译”。JIT编译是动态编译的一种特例。JIT编译一词后来被泛化,时常与动态编译等价;但要注意广义与狭义的JIT编译所指的区别。
3、自适应动态编译(adaptive dynamic compilation)也是一种动态编译,但它通常执行的时机比JIT编译迟,先让程序“以某种式”先运行起来,收集一些信息之后再做动态编译。这样的编译可以更加优化。
PHP JIT 运作原理
Opcache 扩展可以更快的获取 Opcodes 将其直接转到 Zend VM,则 JIT 让它们完全不使用 Zend VM 即可运行。
跳过 Zend VM 并直接被 CPU 执行。 从理论上说,性能会更好。
查看phpinfo()
JIT我们配置 php.ini
opcache.jit=1205
opcache.jit_buffer_size=64M
是否在生成机器码点时候使用AVX指令, 需要CPU支持
0: 不使用
1: 使用
####### 寄存器分配策略
0: 不使用寄存器分配
1: 局部(block)域分配
2: 全局(function)域分配
JIT触发策略
0: PHP脚本载入的时候就JIT
1: 当函数第一次被执行时JIT
2: 在一次运行后,JIT调用次数最多的百分之(opcache.prof_threshold * 100)的函数
3: 当函数/方法执行超过N(N和opcache.jit_hot_func相关)次以后JIT
4: 当函数方法的注释中含有@jit的时候对它进行JIT
5: 当一个Trace执行超过N次(和opcache.jit_hot_loop, jit_hot_return等有关)以后JIT
JIT优化策略,数值越大优化力度越大:
0: 不JIT
1: 做opline之间的跳转部分的JIT
2: 内敛opcode handler调用
3: 基于类型推断做函数级别的JIT
4: 基于类型推断,过程调用图做函数级别JIT
5: 基于类型推断,过程调用图做脚本级别的JIT
关于类名调用测试
php 7.4版本
class ImageService
{
private $src;
private $image;
private $imageinfo;
private $percent = 0.5;
/** 高清压缩图片
* @param string $saveName 提供图片名(可不带扩展名,用源图扩展名)用于保存。或不提供文件名直接显示
*/
public function compressImg($saveName='')
{
}
}
###获取类名 方法一
var_dump (ImageService::class);
//打印结果:string(12) "ImageService"
### 获取类名方法二
$obj = new ImageService();
var_dump(get_class ($obj));
//打印结果:string(12) "ImageService"
php8.0 版本
class ImageService
{
private $src;
private $image;
/** 高清压缩图片
* @param string $saveName 提供图片名(可不带扩展名,用源图扩展名)用于保存。或不提供文件名直接显示
*/
public function compressImg($saveName='')
{
}
}
var_dump($imageObj::class);
//打印结果:string(12) "ImageService"
构造函数可直接定义成员变量
php7.4版本
## php7版本
class MaterialsDao{
private $name;
private $pwd;
public function __construct($name,$pwd)
{
$this->name = $name;
$this->pwd = $pwd;
}
}
var_dump( new MaterialsDao('admin','!$123123%$'));
//打印结果
object(MaterialsDao)#1 (2) {
["name":"MaterialsDao":private]=>
string(5) "admin"
["pwd":"MaterialsDao":private]=>
string(10) "!$123123%$"
}
php8.0版本 直接定义成员变量
## php8版本 构造函数 可直接定义成员变量
class MaterialsPHP8Dao{
public function __construct(private $name,private $pwd)
{
}
}
var_dump( new MaterialsPHP8Dao('admin','!$123123%$'));
//打印结果
object(MaterialsPHP8Dao)#1 (2) {
["name":"MaterialsPHP8Dao":private]=>
string(5) "admin"
["pwd":"MaterialsPHP8Dao":private]=>
string(10) "!$123123%$"
}
字符串的处理
1.判断字符串中是否存在某个字符
php 7.4 版本
$url = "https://www.php.net/releases/8.0/zh.php";
//原来方式@1. strstr
$domain = strstr($url,'http');
echo $domain;
//原来方式@2. strpos
if(strpos($url,'http')!==false || strpos($url,'https')!==false){
echo "包含http或https";
}else{
echo "不包含http";
}
php8.0 版本 新增str_contains函数
$url = "https://www.php.net/releases/8.0/zh.php";
if(str_contains($url,"http")){
echo "包含http或https";
}else{
echo "不包含http";
}
2.判断字符串是否以开头 或 以结尾
php7.4版本
$str = ":测试一下喽";
if (':' == substr($str, 0, 1)) {
echo "ok";
}else{
echo "no";
}
php8.0版本 新增 str_stars_with:开始函数 str_ends_with:结束函数
if(str_starts_with($str,":测试")){
echo "以':测试'开头";
}else{
echo "否";
}
if(str_ends_with($str,"喽")){
echo "以'喽'结束";
}else{
echo "否";
}
3.新的关键字:match, 这个关键字的作用跟switch有点类似。
php7.4版本 switch
switch ($input) {
case "true":
$result = 1;
break;
case "false":
$result = 0;
break;
case "null":
$result = NULL;
break;
}
php 8.0 版本 新关键词match
$result = match($input) {
"true" => 1,
"false" => 0,
"null" => NULL,
};
###多个值
$result = match($input) {
"true", "on" => 1,
"false", "off" => 0,
"null", "empty", "NaN" => NULL,
};
4. 串联优先级
## 串联优先级 测试
$a = 100;
$b = 200;
echo '两数之和:' . $a + $b . PHP_EOL;
// PHP7.* 执行顺序是: ('两数之和:' . $a) + $b .PHP_EOL;
## 打印输出 200
// PHP8执行顺序是: '两数之和:' . ($a + $b) . PHP_EOL;
## 打印输出 300
5. 联合类型 索引
// 参数是联合类型
function paramsUnionType(array|bool $data) {
var_dump($data);
}
// 参数为数组
paramsUnionType(['a', 'd', 'e']);
// 参数为布尔型
paramsUnionType(false);
// 返回值是联合类型
function retUnionType($data) : array|bool|string {
return $data;
}
// 返回值为数组类型
var_dump(retUnionType(['b', 'a', 1]));
// 返回值为布尔类型
var_dump(retUnionType(true));
// 返回值为字符串类型
var_dump(retUnionType('new1024kb'));
// 参数和返回值都是联合类型
function unionType(array|bool $data): bool|array {
return $data;
}
// 数组类型
var_dump(unionType(['a', 'f', 'q']));
// 布尔类型
var_dump(unionType(true));
// 整型(会被转换成bool型 true)
var_dump(unionType(127867));
6.fdiv 函数 允许除数为0
// 除数为0
var_dump(fdiv(2, 0));
var_dump(fdiv(1, 3));
var_dump(fdiv(1, 2));
// intdiv() 对结果取整
// fmod() 返回余数
返回结果:
float(INF)
float(0.3333333333333333)
float(0.5)
get_debug_type和gettype() 区别
$arr = [1, 2, 3];
echo '数组类型' . PHP_EOL;
var_dump('get_debug_type(): '. get_debug_type($arr));
var_dump('gettype(): ' . gettype($arr));
$str = 'new1024kb';
echo '字符串类型' . PHP_EOL;
var_dump('get_debug_type(): ' . get_debug_type($str));
var_dump('gettype(): ' . gettype($str));
echo PHP_EOL;
$i = 1024;
echo '整型' . PHP_EOL;
var_dump('get_debug_type(): ' . get_debug_type($i));
var_dump('gettype(): ' . gettype($i));
echo PHP_EOL;
$str = 10.24;
echo '字符串类型' . PHP_EOL;
var_dump('get_debug_type(): ' . get_debug_type($str));
var_dump('gettype(): ' . gettype($str));
echo PHP_EOL;
$b = false;
echo '布尔型' . PHP_EOL;
var_dump('get_debug_type(): ' . get_debug_type($b));
var_dump('gettype(): ' . gettype($b));
echo PHP_EOL;
class Type{}
$type = new Type();
echo '对象' . PHP_EOL;
var_dump('get_debug_type(): ' . get_debug_type($type));
var_dump('gettype(): ' . gettype($type));
运行结果:
函数 | 参数int型 | 参数string型 | 参数布尔bool型 | 参数数组array型 | 对象浮点型 | 实例化 |
---|---|---|---|---|---|---|
- | int | string | bool | array | float | 实例化 |
get_debug_type | int | string | bool | array | float | 类名 |
gettype | integer | string | boolean | array | double | object |
7. php8 新增参数跳过 参数与顺序无关,且是自描述的。
属性
function named_params($a, $b, $c = 0, $d = 0) {
echo $a."-".$b."-".$c."-".$d;
}
echo "function: ";
named_params(1, 2,d:20 );
##打印结果: 1-2-0-20%
8. NULLsafe
php7.4
$country = null;
if ($session !== null) {
$user = $session->user;
if ($user !== null) {
$address = $user->getAddress();
if ($address !== null) {
$country = $address->country;
}
}
}
php8.0
$country = $session?->user?->getAddress()?->country;
9. PHP 8新特性之Attributes 注释
php7.4 版本
/**
* @param $where
* @param string $field
* @return array
*/
function getOne($where, $field='*'){
return [];
}
$ref = new ReflectionFunction("getOne");
var_dump ( $ref->getDocComment());
## 打印结果
string(6) "author"
array(2) {
[0]=>
string(6) "123123"
[1]=>
string(44) "https://stitcher.io/blog/attributes-in-php-8"
}
php8.0
$ref01 = new ReflectionFunction("getOneById");
var_dump($ref01->getAttributes("Params")[0]->getName());
var_dump($ref01->getAttributes("Params")[0]->getArguments());
var_dump($ref01->getAttributes("See")[0]->getName());
var_dump($ref01->getAttributes("See")[0]->getArguments());
string(3) "see"
array(2) {
[0]=>
string(6) "123123"
[1]=>
string(44) "https://stitcher.io/blog/attributes-in-php-8"
}
#[Params("name", "pwd"),author("123123","https://stitcher.io/blog/attributes-in-php-8")]
function getOneByName($name,$pwd){
return boolval (1);
}
$ref01 = new ReflectionFunction("getOneByName");
var_dump($ref01->getAttributes("Params")[0]->getName());
var_dump($ref01->getAttributes("Params")[0]->getArguments());
string(6) "Params"
array(2) {
[0]=>
string(4) "name"
[1]=>
string(3) "pwd"
}
var_dump($ref01->getAttributes("author")[0]->getName());
var_dump($ref01->getAttributes("author")[0]->getArguments());
string(6) "author"
array(2) {
[0]=>
string(6) "123123"
[1]=>
string(44) "https://stitcher.io/blog/attributes-in-php-8"
}
总结
- 新语法开始面向其他设计語言
- PHP 开始活用强型别写发的特性
- PHP 正在一步一步的要求严谨
- JIT 目前在 PHP 8.0 能提升的情境有限