PHP7新特性
?? 运算符
php7以前用三目判断变量是否存在或是否为空
$a = isset($_GET['a']) ? $_GET['a'] : 1;
php7新增null 合并运算符??
快捷判断
$a = $_GET['a'] ?? 1;
函数返回值类型声明
用:+返回值类型
的形式定义函数的返回值类型
<?phpdeclare(strict_types=1);
function foo($a) : int
{return $a;
}
不过这里也有一个特点需要注意。PHP 7 增加了一个 declare 指令:strict_types,既使用严格模式。
使用返回值类型声明时,如果没有声明为严格模式,如果返回值不是预期的类型,PHP 还是会对其进行强制类型转换。但是如果是严格模式, 则会出发一个 TypeError
的 Fatal error,跟 js 的 strict mode有点类似
标量类型声明
新增了 string
、int
、float
和 bool等
类型的的形式参数类型声明,在 PHP 5 中只能是类名、接口、array 或者 callable
,例如下面的函数中定义int类型的参数$a
function foo(int $a) : int
{return $a;
}
不过还是要在开启严格模式下才会触发错误,否则php还是会对不符合预期的参数进行强制类型转换,严格模式下则触发 TypeError
的致命错误
use 批量声明
PHP 7 中 use 可以在一句话中声明多个类、函数或 const 了
<?php use some\namespace\{ClassA, ClassB, ClassC as C};
use function some\namespace\{fn_a, fn_b, fn_c};
use const some\namespace\{ConstA, ConstB, ConstC};
太空船运算符
也被称为组合比较运算符或三向比较运算符。这个运算符的符号是 <=>
。
太空船运算符用于比较两个表达式。它会返回一个整数,表示这两个表达式的相对顺序:
- 如果左边的值小于右边的值,返回
-1
- 如果左边的值等于右边的值,返回
0
- 如果左边的值大于右边的值,返回
1
这使得在需要对两个值进行比较并得到一个明确的排序结果时非常有用,特别是在排序算法中。
示例:
$a = 5;
$b = 10;$result = $a <=> $b;if ($result === -1) {echo "$a is less than $b";
} elseif ($result === 0) {echo "$a is equal to $b";
} else {echo "$a is greater than $b";
}
输出:
csharp5 is less than 10
这种运算符在某些情况下可以使代码更加简洁和易读,特别是当需要进行连续的比较和赋值操作时。
常量数组
在 PHP 7 中,您可以直接在定义常量时定义常量数组。这是通过使用 define()
函数来完成的,其中第一个参数是常量的名称,第二个参数是要分配给该常量的值。对于数组常量,您需要将数组值作为第二个参数传递,并使用 true
作为第三个参数,以指示该常量是一个数组常量。
以下是如何在 PHP 7 中定义和使用常量数组的示例
// 定义常量数组
define('MY_CONSTANT_ARRAY', [1, 2, 3, 4, 5], true);// 检查常量是否已定义
if (defined('MY_CONSTANT_ARRAY')) {// 使用常量数组$array = MY_CONSTANT_ARRAY;print_r($array);
} else {echo "常量 MY_CONSTANT_ARRAY 未定义。";
}
一旦常量被定义,它的值就不能被改变。尝试更改常量的值将收到一个错误,类似于 “Cannot redefine constant MY_CONSTANT_ARRAY”,这意味着可以定义一个不可改变的数组,从而提高代码的可读性和安全性。
匿名类
匿名类允许你创建没有显式类名的临时类,它们通常用于需要一个简单的一次性对象,而不需要定义完整的类。匿名类特别适用于需要实现某个接口或扩展某个类的简单场景,而不必编写额外的类定义。示例:
// 使用匿名类扩展现有类
class BaseClass {public function showMessage() {echo "Hello from BaseClass!";}
}$extendedObj = new BaseClass();
$extendedObj->showMessage(); // 输出 "Hello from BaseClass!"// 使用匿名类扩展 BaseClass
$extendedObj = new class($extendedObj) extends BaseClass {public function showMessage() {parent::showMessage(); // 调用父类的 showMessage 方法echo " and also from the anonymous child class!";}
};$extendedObj->showMessage(); // 输出 "Hello from BaseClass! and also from the anonymous child class!"
匿名类可以包含属性、方法,以及实现接口或扩展类的要求。由于它们是匿名的,你不能在其他地方引用它们,只能在创建它们的上下文中使用它们。这使得它们非常适合于一次性任务,如临时替换某个类的行为,或者在不需要持久化类定义的情况下进行测试。
异常处理改进
在 PHP 7 中,异常处理得到了几个重要的改进,使得处理异常更加简洁、高效和灵活。以下是 PHP 7 中关于异常处理的一些主要改进:
-
类型化异常:在 PHP 7 之前,异常通常只是普通的对象,而在 PHP 7 中,你可以使用类名来指定一个异常的类型。这允许你更加精确地捕获特定类型的异常,而不是使用通用的
Exception
类。例如:try {// 可能抛出特定类型的异常 } catch (MyCustomException $e) {// 只处理 MyCustomException 类型的异常 }
-
异常链:在 PHP 7 之前,一个异常不能包含另一个异常。在 PHP 7 中,引入了异常链的概念,允许一个异常封装另一个异常,类似于其他语言中的嵌套异常。这有助于保留原始异常的上下文,并允许更详细的错误调试。
try {// 尝试执行可能出错的代码 } catch (Exception $e) {throw new MyCustomException("Something went wrong", 0, $e); }
在这个例子中,
MyCustomException
可以访问原始异常$e
的所有信息。 -
finally 块:在 PHP 7 之前,
try-catch
结构没有finally
块,这意味着无论是否发生异常,一些清理代码可能需要在try
和catch
块中重复。在 PHP 7 中,finally
块被引入,它包含了无论是否捕获到异常都需要执行的代码。try {// 尝试执行代码 } catch (Exception $e) {// 处理异常 } finally {// 无论是否发生异常,都会执行这里的代码 }
-
异常接口的变化:
Exception
接口在 PHP 7 中发生了变化,引入了更多的方法,如getStringRepresentation()
,该方法返回异常的字符串表示形式。同时,Throwable
接口被引入,它是一个所有可被抛出的异常的基类,包括Exception
和Error
。 -
错误和异常的统一处理:PHP 7 引入了
Throwable
接口,它允许你统一处理错误(Error
)和异常(Exception
)。这意味着你可以在一个catch
块中同时捕获错误和异常,尽管在实践中通常建议分开处理它们。
这些改进使得 PHP 的异常处理更加成熟和灵活,帮助开发者编写更加健壮和易于维护的代码。
性能优化
性能优化。PHP7 引入了全新的引擎:Zend Engine 3.0,大幅提高了解释和执行 PHP 代码的速度。相比于 PHP 5.x,PHP7 的性能提升了 2-3 倍。
PHP8新特性
JIT编译器
PHP 8 引入了 JIT (Just-In-Time)编译器(即时编译引擎),可以显著提高代码执行速度。JIT编译器已经集成在了Opcache插件中,只有启动Opcache插件才有效;
开启方法:
1.在php.ini
文件中添加opcache配置,根据需要调整参数值
[opcache]
opcache.enable=1
opcache.enable_cli=1
opcache.jit_buffer_size=128M
opcache.jit=1255
2.将php.ini
这行的注释取消
;zend_extension=opcache #删除前面的;号
3.重启php,在phpinfo()
中查看
或者打印变量,查看on
的值是否为true
<?php
var_dump(opcache_get_status()['jit']);
注意事项:如果开启了opcache并且修改了代码,那么你需要重启php服务
你修改的代码才会生效!!!
命名参数
命名参数允许你在函数调用时明确指定参数的值,而不需要按照函数定义中的参数顺序传递参数。这可以提高代码的可读性和可维护性,特别是在处理具有多个可选参数的函数时。
要使用命名参数,你需要在函数调用时使用参数名称来指定参数的值。参数名称和值之间使用冒号(:)进行分隔。以下是一个示例
<?php
function createUser($name, $age=18, $email, $password = 'password123') {echo $name, $age=18, $email, $password = 'password123';
}// 使用命名参数调用函数,只指定 $name 和 $email
createUser(name: 'John', email: 'john@example.com'); // 使用 $age 的默认值 18 和 $password 的默认值 'password123'
联合类型
联合类型允许一个变量、函数或方法的参数和返回值接受多种不同的类型。这增加了类型系统的灵活性,并有助于在开发过程中提供更准确的类型检查。
联合类型使用竖线(|)分隔多个类型,表示变量、参数或返回值可以是这些类型中的任何一个。以下是一些使用联合类型的示例:
// 变量声明
$variable = 'hello'; // string 类型
$variable = 42; // int 类型
$variable = 4.2; // float 类型
$variable = true; // bool 类型
$variable = null; // null 类型// 函数参数
function processValue(mixed $value): void {// 处理 $value,它可以是任何类型
}// 方法返回值
class Example {public function getValue(): int|float {// 返回 int 或 float 类型的值}
}// 类属性
class User {public function __construct(private string|int $id) {// 构造函数接受 string 或 int 类型的 $id}
}// 类型断言
$value = '42';
if ($value is int|float) {echo "The value is an integer or a float.";
}
联合类型不会改变变量的实际类型,它们只是提供了一种方式来描述变量可能持有的多种类型。在运行时,变量的实际类型仍然是确定的,并且可以通过类型断言或其他方式来检查和操作。
属性改进
-
属性初始化: 在 PHP 8 之前,类的属性必须在构造函数中进行初始化。然而,在 PHP 8 中,你可以直接在属性声明时为其赋予默认值,这样就不需要再在构造函数中进行初始化。
class MyClass {public $myProperty = 'default value'; // 直接在属性声明时初始化 }
-
属性类型声明: PHP 8 引入了更严格的类型系统,允许你在属性声明时指定其类型。这有助于在开发过程中捕获类型错误,并提高代码的可读性和可维护性。
class MyClass {public int $myIntProperty; // 指定属性类型为 int }
-
只读属性:
PHP 8 引入了只读属性(read-only properties)的概念。使用 public readonly 关键字定义的属性只能在对象构造时或在 __construct 方法内部被赋值,之后就不能再修改了。这有助于确保对象的不变性。class MyClass {private $myProperty;public function __construct() {$this->myProperty = 'secret';}public function revealProperty(): string {return $this->myProperty; // 传统的 getter 方法} }$obj = new MyClass(); echo $obj->revealProperty(); // 输出 "secret"// 在 PHP 8 中,你也可以这样直接读取私有属性的值(不推荐,因为破坏了封装性) echo $obj->myProperty; // 输出 "secret"
match表达式
match
表达式允许你根据表达式的值来匹配不同的情况,并执行相应的代码块。它使用了一种类似于数组解构的语法,使得代码更加简洁和直观。
下面是一个使用 match
表达式的示例:
$number = 5;$result = match ($number) {1, 2, 3 => 'Low',4, 5, 6 => 'Medium',7, 8, 9 => 'High',default => 'Unknown',
};echo $result; // 输出 "Medium"
match
表达式的语法比传统的 switch
语句更加简洁,并且支持多个值匹配同一个结果,这使得代码更加易读和易于维护。
需要注意的是,match
表达式在 PHP 8 中是作为一种表达式存在的,它会返回一个值,而不是像 switch
语句那样仅仅执行代码块。因此,你可以将 match
表达式的结果赋值给一个变量,或者在更大的表达式中使用它。
Nullsafe 运算符
在 PHP 8 中,引入了一个新的运算符叫做 Nullsafe 运算符(?->
)。这个运算符提供了一种安全的方式来访问对象的属性或调用对象的方法,而不需要担心对象本身是否为 null
。在 PHP8以前的版本 中,如果你尝试访问一个 null
对象的属性或方法,将会引发一个错误。为了避免这种情况,开发者通常需要在使用对象之前进行空值检查。然而,这会导致代码变得冗长且难以阅读。
Nullsafe 运算符的引入解决了这个问题。它允许你在不进行显式空值检查的情况下安全地访问对象的属性或方法。如果对象本身是 null
,Nullsafe 运算符将返回 null
,而不会引发错误。
class User {public $name;public function getName() {return $this->name;}
}$user = null;// 使用传统的方式访问属性或方法会引发错误
// echo $user->name; // Error: Trying to get property 'name' of non-object
// echo $user->getName(); // Error: Calling a member function getName() on null// 使用 Nullsafe 运算符安全地访问属性或方法
echo $user?->name; // 输出 null,而不是引发错误
echo $user?->getName(); // 输出 null,而不是引发错误
字符串与数字的比较
PHP 8 比较数字字符串(numeric string)时,会按数字进行比较。 不是数字字符串时,将数字转化为字符串,按字符串比较。
0 == 'foobar' // php7执行结果为:true
0 == 'foobar' // php8执行结果为:false
构造器属性提升
这个新的语法糖来用来创建值对象或数据传输对象。不用为类属性和构造函数指定它们,PHP 现在可以将它们合并为一个。
php7定义类属性和构造方法赋值:
class Money
{public Currency $currency;public int $amount;public function __construct(Currency $currency,int $amount,) {$this->currency = $currency;$this->amount = $amount;}
}
php8合并定义类属性和构造方法赋值:
class Money
{public function __construct(public Currency $currency,public int $amount,) {}
}
其他调整
更多细节调整参考官方文档
PHP: PHP 8.0.0 Release Announcement