php8新特性
命名参数
function foo(string $a, string $b, ?string $c = null, ?string $d = null)
{ /* … */ }
你可以通过下面的方式传入参数进行调用
foo(
b: 'value b',
a: 'value a',
d: 'value d',
);
联合类型
php7
class Number {
/** @var int|float */
private $number;
/**
* @param float|int $number
*/
public function __construct($number) {
$this->number = $number;
}
}
new Number('NaN'); // Ok
php8
class Number {
public function __construct(
private int|float $number
) {}
}
new Number('NaN'); // TypeError
新的 mixed类型
mixed本身是以下类型之一:
array
bool
callable
int
float
null
object
resource
string
function bar(): ?mixed {}
nullsafe运算符
//现在可以用新的 nullsafe 运算符链式调用,而不需要条件检查 null。 如果链条中的一个元素失败了,整个链条会中止并认定为 Null。
$country = null;
if ($session !== null) {
$user = $session->user;
if ($user !== null) {
$address = $user->getAddress();
if ($address !== null) {
$country = $address->country;
}
}
}
//简化为一行代码
$country = $session?->user?->getAddress()?->country;
str_contains()、str_starts_with()和str_ends_with()函数
有些人可能会说它早就该有了,但我们终于不必再依赖strpos() 来知道字符串是否包含另一个字符串了。
//判断$s 中是否存在words
$s = 'string with lots of words';
if (str_contains($s, 'words')) { /* … */ }
str_starts_with('haystack', 'hay'); // true 判断开头
str_ends_with('haystack', 'stack'); // true 判断结尾
WeakMap类
WeakMap是将对象作为key来访问的map。也就是说,WeakMap中的键是存储另一个对象的引用,一旦另一个对象被删除,该WeakMap的key的引用也会断开。
不使用WeakMap的案例
<?php
// 房子
class House
{
public function __construct(public array $rooms = [])
{
}
// 添加人
public function addPerson(Person $person)
{
$this->rooms[$person->name] = $person;
}
}
// 人
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人
unset($lucy); // 删除1人
echo count($house->rooms); // 还是2人
// 这个人还在
$lucyObj = $house->rooms['lucy'];
echo $lucyObj->name; // lucy
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这个人已经走了
print_r($lucyObj);
// 通过调用WeakMap中提供的迭代器方法来查看其他租客信息
foreach ($house->rooms->getIterator() as $k => $v) {
print_r($k);
}
==============php7新特================
标量类型的声明
标量类型声明有两种模式: 强制 (默认) 和 严格模式。 现在可以使用下列类型参数(无论用强制模式还是严格模式): 字符串(string), 整数 (int), 浮点数 (float), 以及布尔值 (bool)。它们扩充了PHP5中引入的其他类型:类名,接口,数组和 回调类型。
PHP标量包含: 字符串(string), 整数 (int), 浮点数 (float), 以及布尔值 (bool)。
php函数接受多个参数
function getNum(){
$arr = func_get_args(); //获取全部
print_r(func_get_arg(1)); // 获取第几个参数
print_r($arr);
}
getNum(1,"qwer",[1,2,3]);
function sumOfInts(int ...$ints)
{
print_r(func_get_args()); // 获取第几个参数
}
sumOfInts(1,2,3);
返回值类型声明
/**
* ?array 表示必须传入数组或者null,否则报错
* : ?array 表示返回必须是数组或者null,否则报错
*/
function arraysSum(?array $arrays): ?array
{
return $arrays;
}
var_dump(arraysSum([6]));
/**
* @param $s
* @return string|null
* 如果输入参数$s 没有限定的话,输入int类型会转换为string,如果数组array类型会报错
*/
function stringTest($s): ?string
{
return $s;
}
var_dump(stringTest(5));
/**
* @param int|null $a
* @param int|null $b
* @return int|null 如果返回字符串,则会被转换为int类型
*/
function sum(?int $a, ?int $b): ?int{
if ($a == null || $b == null) {
return null;
}
return $a + $b;
}
var_dump(sum(1,2));
/**
* @return void
* :void 明确表示该函数没有返回值,可以省略return也可以只写return
* 该函数返回null
*/
function testReturn(): void
{
return ;
}
var_dump(testReturn()); // null
null合并运算符
$a ?? 0 等同于 isset($a) ? $a : 0
$a ?: 0 等同于 $a ? $a : 0
empty: 判断一个变量是否为空(null、false、00、0、’0′、』这类,都会返回true)
isset: 判断一个变量是否设置(值为false、00、0、’0′、』这类,也会返回true)
// 定义之前
print_r($name ?? 'Tom');
// Tom
print_r($name ?: 'Jack');
// Jack
// Undefined variable: name
// 定义之后
$name = '';
print_r($name ?? 'Tom');
// ''
print_r($name ?: 'Jack');
// Jack
$a = 0;
$b = 1;
var_dump($a ?? $b); // int(0)
var_dump(isset($a) ? $a : $b); // int(0)
var_dump($a ?: $b); // int(1)
var_dump($a ? $a : $b); // int(1)
太空船操作符(组合比较符)
太空船操作符用于比较两个表达式。当$a小于、等于或大于$b时它分别返回-1、0或1。 比较的原则是沿用 PHP 的常规比较规则进行的。
// 整数
echo 1 <=> 1; // 0
echo 1 <=> 2; // -1
echo 2 <=> 1; // 1
// 浮点数
echo 1.5 <=> 1.5; // 0
echo 1.5 <=> 2.5; // -1
echo 2.5 <=> 1.5; // 1
// 字符串
echo "a" <=> "a"; // 0
echo "a" <=> "b"; // -1
echo "b" <=> "a"; // 1
匿名类
现在支持通过new class 来实例化一个匿名类,这可以用来替代一些“用后即焚”的完整类定义。
<?php
interface Logger {
public function log(string $msg);
}
class Application {
private $logger;
public function getLogger(): Logger {
return $this->logger;
}
public function setLogger(Logger $logger) {
$this->logger = $logger;
}
}
$app = new Application;
$app->setLogger(new class implements Logger {
public function log(string $msg) {
echo $msg;
}
});
var_dump($app->getLogger());
?>
namespace 导入的类
// PHP 7 之前的代码
use some\namespace\ClassA;
use some\namespace\ClassB;
use some\namespace\ClassC as C;
use function some\namespace\fn_a;
use function some\namespace\fn_b;
use function some\namespace\fn_c;
use const some\namespace\ConstA;
use const some\namespace\ConstB;
use const some\namespace\ConstC;
// PHP 7+ 及更高版本的代码
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};
整数除法函数 intdiv()
<?php
//新加的函数 intdiv() 用来进行 整数的除法运算。
var_dump(intdiv(10, 3)); // int(3)
?>
random_bytes函数
// 一般配合bin2hex()函数使用
// bin2hex()把ASCII字符串转换为十六进制值
echo bin2hex(random_bytes(10));
random_bytes() 每次调用都会生成不同内容的二进制字符串,而参数则是二进制的字节长度。直接获取到的二进制数据是乱码格式的,所以一般我们会需要使用 bin2hex() 来将二进制转换成我们可以看懂的十六进制格式字符串。不过由此带来的结果就是我们转换之后的十六进制的字符长度是我们设定的字符长度的 2 倍。这个函数的作用,可以为我们生成安全的用户密码 salt 、 密钥关键字 或者 初始化向量。
原错误内容:random_bytes() 每次调用都会生成不同内容的字符串,而参数则是字符长度的随机字符,在这里我们传递的是 5 ,返回了 10 个字符,可以看出这个参数是字符数量,而返回的其实是字节数量,对应一个字符占用两个字节的返回形式。或者我们就直接记住它返回的就是参数的两倍即可。至于这个函数的作用嘛,可以为我们生成安全的用户密码 salt 、 密钥关键字 或者 初始化向量
数组展开运算
$arrayA = [1, 2, 3];
$arrayB = [4, 5];
$result = [0, ...$arrayA, ...$arrayB, 6 ,7];
// [0, 1, 2, 3, 4, 5, 6, 7]
类常量可见性
class Sky8g
{
const PUBLIC_CONST_A = 1;
public const PUBLIC_CONST_B = 2;
protected const PROTECTED_CONST = 3;
private const PRIVATE_CONST = 4;
}
多异常捕获处理
<?php
try {
// some code
} catch (FirstException | SecondException $e) {
// handle first and second exceptions
}
<?php
//创建四个exception的子类,每个子类中分别有一个可以解决异常问题的方法
class wcexception extends exception{
function pro(){
echo "去公厕上厕所<br>";
}
}
class noexception extends exception{
function pro(){
echo "去公司附近吃早餐<br>";
}
}
class gsexception extends exception{
function pro(){
echo "走普通的公路<br>";
}
}
class luexception extends exception{
function pro(){
echo "换上备胎<br>";
}
}
//定义一个类,包含四种方法对应四种行为,用条件判断如果行为有异常则抛出异常
class dm{
function gowc($bj){
if(!$bj){
throw new wcexception("倒霉催的,厕所坏了<br>");
}
echo "上厕所顺利<br>";
}
function zc($time){
if(!$time){
throw new noexception("没时间吃早餐了<br>");
}
echo "早餐很好吃<br>";
}
function sgs($xx){
if(!$xx){
throw new gsexception("下雪高速封路<br>");
}
echo "上高速很顺利<br>";
}
function drive($dz){
if(!$dz)
throw new luexception("车子爆胎了<br>");
echo "开车一路顺利<br>";
}
}
echo "早上起床!<br>";
try{
//创建一个对象,下面调用四个方法分别对应四种可能导致异常的行为
$ob=new dm();
//上厕所
$ob->gowc(true);
//吃早餐
$ob->zc(true);
//上高速
$ob->sgs(false);
//开车
$ob->drive(false);
}
//一个try可以对应多个catch
catch(wcexception $e){
echo $e->getmessage();
$e->pro();
}
catch(noexception $e){
echo $e->getmessage();
$e->pro();
}
catch(gsexception $e){
echo $e->getmessage();
$e->pro();
}
//最后一个catch中可以不用exception的子类,这样可以用来捕获漏网之鱼,但不能写出解决方案;
catch(exception $e){
echo $e->getmessage();
$e->pro();
}
echo "到公司开始工作<br>";
?>
list()现在支持键名
$data = [
["id" => 1, "name" => 'Tom'],
["id" => 2, "name" => 'Fred'],
];
// list() style
list("id" => $id1, "name" => $name1) = $data[0];
echo $id1,$name1;//1Tom
支持为负的字符串偏移量
var_dump("abcdef"[-2]);//string (1) "e"
新的对象类型
这种新的对象类型object, 引进了可用于逆变(contravariant)参数输入和协变(covariant)返回任何对象类型。
<?php
function test(object $obj) : object
{
return new SplQueue();
}
test(new StdClass());
类型属性
//类属性现在支持类型声明。
<?php
class User {
public int $id;
public string $name;
}
?>
箭头函数
<?php
$factor = 10;
$nums = array_map(fn($n) => $n * $factor, [1, 2, 3, 4]);
// $nums = array(10, 20, 30, 40);
//短闭包函数
array_map(function (User $user) {
return $user->id;
}, $users)
?>
合并数组新方式
<?php
$parts = ['apple', 'pear'];
$fruits = ['banana', 'orange', ...$parts, 'watermelon'];
// ['banana', 'orange', 'apple', 'pear', 'watermelon'];
?>
define() 定义常量数组
define('ANIMALS', [
'dog',
'cat',
'bird'
]);
echo ANIMALS[1]; // 输出 "cat
将callback 转闭包
Closure新增了一个静态方法,用于将callable快速地 转为一个 Closure 对象。
<?php
class Test
{
public function exposeFunction()
{
return Closure::fromCallable([$this, 'privateFunction']);
}
private function privateFunction($param)
{
var_dump($param);
}
}
$privFunc = (new Test)->exposeFunction();
$privFunc('some value');
新增数组函数 array_key_first(), array_key_last()
$array = ['a'=>'1','b'=>'2'];
#php 7.3之前
$firstKey = key(reset($array));
# php 7.3
$firstKey = array_key_first($array);//a
$lastKey = array_key_last($array);//b