PHP8.0已经在2020年11月26号发布,到现在最新版,已经是PHP8.2.2,本站leyeah.com已经升级至最新版,PHP8的升级势在必行,可能很多网站,依旧还是在使用PHP7,可以考虑找个时间升级一下,毕竟新版发布都2年有余,性能方便提升不少,也增加了一些新功能,阿里云的Alibaba Cloud Linux 3或Centos的用户可以参考下这篇文章。
Alibaba Cloud Linux 3或centos如何升级到PHP8以上
PHP8提供了哪些新特性呢,可以参照下PHP8的官方release note,上面有对功能做了详细的说明。
1. 命名参数
在一个函数参数多达5,6个时,并且需要传最后一个参数时,前面本来可以默认的也必须传过去,有了命名参数后,就会方便很多,举个例子来说明下。
function test($a, $b = 1, $c = 2, $d = 3, $e = 4, $f = 5)
{
echo $a + $b + $c + $d + $e + $f;
}
//PHP7
test(0, 1, 2, 3, 4, 10); //输出 20
//PHP8
test(0, f: 10); //输出 20
对比一下,命名参数前面不能带上$符号,这个要注意一下,看起来是不是方便很多,可读性也强一些。
2. 注解的变化,就引用下官方的例子,看起来方式变得简便一些。
//PHP 7
class PostsController
{
/**
* @Route("/api/posts/{id}", methods={"GET"})
*/
public function get($id) { /* ... */ }
}
//PHP 8
class PostsController
{
#[Route("/api/posts/{id}", methods: ["GET"])]
public function get($id) { /* ... */ }
}
3. 构造器属性提升
//PHP 7
class Point {
public float $x;
public float $y;
public float $z;
public function __construct(
float $x = 0.0,
float $y = 0.0,
float $z = 0.0
) {
$this->x = $x;
$this->y = $y;
$this->z = $z;
}
}
//PHP8
class Point {
public function __construct(
public float $x = 0.0,
public float $y = 0.0,
public float $z = 0.0,
) {}
}
可以看出,写法上简便很多。
4. 增加了联合类型
//PHP8
function test(int $a, int|string $b): mixed
{
if (is_numeric($b)) {
return $a + $b;
} else {
return $a . ' ' . $b;
}
}
echo test(2, 6); //输出 8
echo test(2, 'hello');//输出 2 hello
从列子中看出,$b参数可以传入多个类型声明,这个对某些情况会很有用,以前只能在注释里标记,现在方法里可以直接声明,方便不少。
mixed类型是以下里面的一种。
array
bool
callable
int
float
null
object
resource
string
需要注意的是,null不能作为单独的类型,如下:
function test (null $a); // 不可以
function test (int|null $a); // 可以
还有oject和resource也不能一起用,如下:
function test (object|resource $a); // 不可以
function test (int|resource $a); // 可以
5. 增加了match表达式,看下面例子
//PHP 7 or PHP 8
$a = 1;
switch ($a) {
case 1:
echo 'hello 1';
break;
case 2:
echo 'hello 2';
break;
default:
echo 'hello';
break;
}
//上述结果 hello 1
//PHP 8
$a = 1;
echo match ($a) {
1 => 'hello 1',
2 => 'hello 2',
default => 'hello',
};
//上述结果 hello 1
需要注意PHP8中变量$a是区分数据类型的,变成这样,结果就不同,这点需要格外注意。
//PHP7
$a = '1';
switch ($a) {
case 1:
echo 'hello 1';
break;
case 2:
echo 'hello 2';
break;
default:
echo 'hello';
break;
}
//上述结果 hello 1
//PHP 8
$a = '1';
echo match ($a) {
1 => 'hello 1',
2 => 'hello 2',
default => 'hello',
};
//上述结果 hello
6. 增加了nullsafe操作符,看以下例子:
//PHP8
class TestClass
{
public function __construct(object|null $dog)
{
######## 写法简单 #######
$dog?->cat?->saying();
}
}
class Dog
{
public $cat;
public function __construct()
{
$this->cat = new Cat();
}
public function saying(): void{
echo 'Wang wang';
}
}
class Cat
{
public function saying(): void{
echo 'Miao miao';
}
}
new TestClass(new Dog()); //输出 Miao miao
new TestClass(null); //输出为空
本来多种判断的,现在加几个?就解决了,$dog?->cat?->saying(); 确实方便很多了。
第一个变量还是要有的,如果你直接写$dog?->cat?->saying(); 还是会报错的。
7. 改进了字符串和数字的比较,看下例子:
//PHP7
var_dump(0 == '0'); // 输出 bool(true)
var_dump(0 == ''); // 输出 bool(true)
var_dump('0' == ''); // 输出 bool(false) 不能理解吧,为何会不相等,上面都连等了。
//PHP8
var_dump(0 == '0'); // 输出 bool(true)
var_dump(0 == ''); // 输出 bool(false)
var_dump('0' == ''); // 输出 bool(false)
与其说改进,还不如说修了个bug,这个可能对有些对于空或0的判断要格外注意,一不小心,可能就是一个大bug,类型这种情况。
//PHP7
var_dump(44 == '44aaa'); 输出 bool(true)
//PHP8
var_dump(44 == '44aaa'); 输出 bool(false)
8. 内部函数类型错误的一致性,这个看下就行,错误级别不太一样而已。
//PHP 7
strlen([]); // Warning: strlen() expects parameter 1 to be string, array given
array_chunk([], -1); // Warning: array_chunk(): Size parameter expected to be greater than 0
//PHP8
strlen([]); // TypeError: strlen(): Argument #1 ($str) must be of type string, array given
array_chunk([], -1); // ValueError: array_chunk(): Argument #2 ($length) must be greater than 0
9. 即时编译,这个看看官方的说明就行。
PHP 8 引入了两个即时编译引擎。 Tracing JIT 在两个中更有潜力,它在综合基准测试中显示了三倍的性能, 并在某些长时间运行的程序中显示了 1.5-2 倍的性能改进。 典型的应用性能则和 PHP 7.4 不相上下。
关于 JIT 对 PHP 8 性能的贡献
10. static和self可以作为返回类型,看一下例子:
//PHP8
class Animal
{
public static function instance(): self|static
{
return new static();
}
public function saying(): void
{
echo 'No sound';
}
}
class Dog extends Animal
{
public function saying(): void
{
echo 'Wang wang';
}
}
class Cat extends Animal
{
public function saying(): void
{
echo 'Miao miao';
}
}
Animal::instance()->saying(); //输出 No sound
Dog::instance()->saying(); //输出 Wang wang
Cat::instance()->saying(); //输出 Miao miao
11. throw new \Exception('') 从以前的声明用,现在也可用于表达式结构,看一下例子:
//PHP7
try {
$foo = $bar['offset'] ?? throw new \Exception('test');
} catch(\Exception $e) {
echo 'get exception';
}
//以上结果会出现语法解析错误:
#PHP Parse error: syntax error, unexpected 'throw' (T_THROW) in /test/php8.php on line 3
//PHP8
try {
$foo = $bar['offset'] ?? throw new \Exception('test');
} catch(\Exception $e) {
echo 'get exception';
}
//以上结果输出 get exception
12. 增加了类Weakmap,看下面的例子,看看它有什么用:
//PHP7 or PHP8
// 房子
class House
{
public $rooms;
public function __construct(array $rooms = [])
{
$this->rooms = $rooms;
}
// 添加人
public function addPerson(Person $person)
{
$this->rooms[$person->name] = $person;
}
}
// 人
class Person
{
public $name;
public function __construct(string $name)
{
$this->name = $name;
}
}
$house = new House();
$lucy = new Person('lucy');
$jony = new Person('jony');
// 为房子添加人
$house->addPerson($lucy);
$house->addPerson($jony);
//计数
echo count($house->rooms); // 输出 2
unset($lucy); // 删除1人
//$luch已经删除,想得到的结果是1人
echo count($house->rooms); // 输出 2
// 这个人还在
$lucyObj = $house->rooms['lucy'];
//理论上$luch应该不存在了
echo $lucyObj->name; // 输出 lucy
//PHP8 Weakmap写法
class House
{
public WeakMap $rooms;
public function __construct()
{
// 实例化 WeakMap
$this->rooms = new WeakMap();
}
public function addPerson(Person $person)
{
// 注意,这里的键一定是要一个对象
$this->rooms[$person] = $person->name;
}
}
class Person
{
public function __construct(public string $name){}
}
// 房东
$house = new House();
// 租房的人
$lucy = new Person('lucy');
$jony = new Person('jony');
// 租房并给要钥匙
$house->addPerson($lucy);
$house->addPerson($jony);
// 查看租房人数
echo count($house->rooms); // 输出 2
// lucy不租了(删除引用)
unset($lucy);
// 再次查看租房人数
echo count($house->rooms); // 输出 1
$lucyObj = $house->rooms['lucy'];
// 会报以下错误,lucy这个人已经走了
#PHP Fatal error: Uncaught TypeError: WeakMap key must be an object in /test/php8.php:44
#Stack trace:
#0 {main}
# thrown in /test/php8.php on line 44
13. ::class可以用于实例化后的类,看以下例子
//PHP7
$obj = new \stdClass();
echo $obj::class;
//结果会报以下错误:
#PHP Fatal error: Dynamic class names are not allowed in compile-time ::class fetch in /test/php8.php on line 4
//PHP8
$obj = new \stdClass();
echo $obj::class;
//输出 stdClass
14. Exception可以不用定义变量,看以下例子:
//PHP7
try {
throw new \Exception();
} catch (\Exception) {
echo "Something went wrong";
}
//结果报以下错误:
#PHP Parse error: syntax error, unexpected ')', expecting '|' or variable (T_VARIABLE) in /test/php8.php on line 5
//PHP8
try {
throw new \Exception();
} catch (\Exception) {
echo "Something went wrong";
}
//结果输出 Something went wrong
15. 方法参数最后的逗号被允许,看以下例子:
//PHP7
function test($a, $b,)
{
echo $a + $b;
}
test(3, 5);
//结果会报以下错误:
#PHP Parse error: syntax error, unexpected ')', expecting variable (T_VARIABLE) in /test/php8.php on line 2
//PHP8
function test($a, $b,)
{
echo $a + $b;
}
test(3, 5);
//输出 8
16. 增加了Stringable的接口,看一下例子:
//PHP8
class Foo
{
public function __toString(): string
{
return 'foo';
}
}
function bar(string|Stringable $str)
{
echo $str;
}
bar(new Foo()); //输出 foo
bar('abc');//输出 abc
17. 增加了str_contains, str_starts_with, str_ends_with, fdiv, get_debug_type, get_resource_id方法
var_dump(str_contains('string with lots of words', 'words')); //输出 bool(true)
var_dump(str_starts_with('haystack', 'hay')); //输出 bool(true)
var_dump(str_ends_with('haystack', 'stack')); //输出 bool(true)
以上是一些PHP8的新特性,当然还有一些其他方面的改动,请自行查阅相关文档即可。