php 语法特性

php 语法特性

目录

7.0

  • 请求参数和返回值类型声明

请求参数和返回值需要和声明的类型一致

  • null合并运算符

由于日常使用中存在大量同时使用三元表达式和 isset()的情况, 我们添加了null合并运算符 (??) 这个语法糖。如果变量存在且值不为null, 它就会返回自身的值,否则返回它的第二个操作数。

<?php
// 获取 $GET['user']的值,如果该值不存在,则返回'nobody'。
$username = $_GET['user'] ?? 'nobody';
// 这相当于:
$username = isset($_GET['user']) ? $_GET['user'] : 'nobody';

// 存在user返回user 否则存在user1 返回user1 最后返回 nobody
$username = $_GET['user'] ?? $_GET['user1'] ?? 'nobody';
  • 组合比较符

太空船操作符用于比较两个表达式。当$a小于、等于或大于$b时它分别返回-1、0或1。 比较的原则是沿用 PHP 的常规比较规则进行的。

<?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
  • 通过 define() 定义常量数组

Array 类型的常量现在可以通过 define() 来定义。在 PHP5.6 中仅能通过 const 定义。

<?php
define('ANIMALS', [
    'dog',
    'cat',
    'bird'
]);

echo ANIMALS[1]; // 输出 "cat"
  • 生成器

现在,只需在最外层生成其中使用 yield from, 就可以把一个生成器自动委派给其他的生成器, Traversable 对象或者 array。

<?php
function gen()
{
    yield 1;
    yield 2;

    yield from gen2();
}

function gen2()
{
    yield 3;
    yield 4;
}

foreach (gen() as $val)
{
    echo $val, PHP_EOL;
}
// 1 2 3 4
  • 整数除法函数 intdiv()

新加的函数 intdiv() 用来进行 整数的除法运算.

<?php
var_dump(intdiv(10, 3));
// 3

▲ 回顶部

7.1

  • 可为空(Nullable)类型

参数以及返回值的类型现在可以通过在类型前加上一个问号使之允许为空。 当启用这个特性时,传入的参数或者函数返回的结果要么是给定的类型,要么是 null 。

<?php
function testReturn(): ?string
{
    return 'elePHPant';
}

var_dump(testReturn()); // elePHPant

function testReturn1(): ?string
{
    return null;
}

var_dump(testReturn1()); // null

function test(?string $name)
{
    var_dump($name);
}

test('elePHPant'); // elePHPant
test(null); // null
test(); // Uncaught Error: Too few arguments to function test(), 0 passed in...
  • Void 函数

一个新的返回值类型void被引入。 返回值声明为 void 类型的方法要么干脆省去 return 语句,要么使用一个空的 return 语句。 对于 void 函数来说,null 不是一个合法的返回值。

<?php
function swap($left, $right) : void
{
    if ($left === $right) {
        return;
    }
}
var_dump(swap(1, 2)); // null
  • list 可用 [] 替换 且支持键名

短数组语法([])现在作为list()语法的一个备选项,可以用于将数组的值赋给一些变量(包括在foreach中)。

<?php
$data = [
    ["id" => 1, "name" => 'Tom'],
    ["id" => 2, "name" => 'Fred'],
];

// list() style
list("id" => $id1, "name" => $name1) = $data[0];

// [] style
["id" => $id1, "name" => $name1] = $data[0];
  • 类常量可见性

现在起支持设置类常量的可见性。

<?php
class ConstDemo
{
    const PUBLIC_CONST_A = 1;
    public const PUBLIC_CONST_B = 2;
    protected const PROTECTED_CONST = 3;
    private const PRIVATE_CONST = 4;
}
  • 多异常捕获处理

一个catch语句块现在可以通过管道字符(|)来实现多个异常的捕获。 这对于需要同时处理来自不同类的不同异常时很有用。

<?php
try {
    // some code
} catch (FirstException | SecondException $e) {
    // 处理第一个和第二个异常
}
  • 支持为负的字符串偏移量

现在所有支持偏移量的字符串操作函数 都支持接受负数作为偏移量,包括通过[]或{}操作字符串下标。在这种情况下,一个负数的偏移量会被理解为一个从字符串结尾开始的偏移量。

<?php
var_dump("abcdef"[-2]); //e
var_dump(strpos("aabbcc", "b", -3)); // 3
  • 通过 Closure::fromCallable() 将callables转为闭包

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'); // some value

▲ 回顶部

7.2

  • 新的对象类型

这种新的对象类型, object, 引进了可用于逆变(contravariant)参数输入和协变(covariant)返回任何对象类型。

<?php
function test(object $obj) : object
{
    return new SplQueue();
}

test(new StdClass());
  • 允许重写抽象方法(Abstract method)

当一个抽象类继承于另外一个抽象类的时候,继承后的抽象类可以重写被继承的抽象类的抽象方法。

<?php
abstract class A
{
    abstract function test(string $s);
}
abstract class B extends A
{
    // 覆盖-仍然保持参数的逆变和返回的协方差
    abstract function test($s) : int;
}

▲ 回顶部

7.4

  • 属性添加限定类型

类的属性中现在支持添加指定的类型。

<?php
class User {
    public int $id;
    public string $name;
}
//会强制要求 $user->id 只能为 int 类型,同时 $user->name 只能为 string 类型。
  • 箭头函数

箭头函数 提供了一种更简洁的定义函数的方法。。

<?php
$y = 1;

$fn1 = fn($x) => $x + $y;
// 相当于通过 value 使用 $y:
$fn2 = function ($x) use ($y) {
    return $x + $y;
};

var_export($fn1(3)); // 4
  • 空合并运算符赋值
<?php
$array['key'] ??= 'xxx';
// 等同于以下旧写法
if (!isset($array['key'])) {
    $array['key'] = 'xxx';
}
  • 数组展开操作
<?php
$parts = ['apple', 'pear'];
$fruits = ['banana', 'orange', ...$parts, 'watermelon'];
// ['banana', 'orange', 'apple', 'pear', 'watermelon'];

▲ 回顶部

8.0

  • 命名参数

仅仅指定必填参数,跳过可选参数。参数的顺序无关

<?php
// 使用位置参数:
array_fill ( 0 ,  100 ,  50 ) ;
 
// 使用命名参数:
array_fill ( start_index :  0 , num :  100 , value :  50 ) ;
  • 注解

现在可以用 PHP 原生语法来使用结构化的元数据,而非 PHPDoc 声明。

<?php
class PostsController
{
    #[Route("/api/posts/{id}", methods: ["GET"])]
    public function get($id) { /* ... */ }
}
  • 构造器属性提升

当构造器参数带访问控制时,PHP 会同时把它当作对象属性和构造器参数, 并赋值到属性。 构造器可以是空的,或者包含其他语句。 参数值赋值到相应属性后执行正文中额外的代码语句。

<?php
class Point {
  public function __construct(
    public float $x = 0.0,
    public float $y = 0.0,
    public float $z = 0.0,
  ) {}
}
  • 联合类型

联合类型接受多个不同的类型做为参数

<?php
class Number {
  public function __construct(
    private int|float $number
  ) {}
}
new Number('NaN'); // TypeError
new Number(1);
  • Match 表达式

match 表达式基于值的一致性进行分支计算。 match表达式和 switch 语句类似, 都有一个表达式主体,可以和多个可选项进行比较。 与 switch 不同点是,它会像三元表达式一样求值。 与 switch 另一个不同点,它的比较是严格比较( ===)而不是松散比较(==)

<?php
echo match (8.0) {
  '8.0' => "Oh no!",
  8.0 => "This is what I expected",
};
//> This is what I expected
  • Nullsafe 运算符

现在可以用新的 nullsafe 运算符链式调用,而不需要条件检查 null。 如果链条中的一个元素失败了,整个链条会中止并认定为 Null。

<?php
//php7
$country =  null;
if ($session !== null) {
  $user = $session->user;
  if ($user !== null) {
    $address = $user->getAddress();
 
    if ($address !== null) {
      $country = $address->country;
    }
  }
}
//php8
$country = $session?->user?->getAddress()?->country;
  • 字符串与数字的比较更符合逻辑

PHP 8 比较数字字符串(numeric string)时,会按数字进行比较。 不是数字字符串时,将数字转化为字符串,按字符串比较。

<?php
//php7
0 == 'foobar' // true
//php8
0 == 'foobar' // false

▲ 回顶部

8.1

  • 枚举

Enum 类似 class,它和 class、interface、trait 共享同样的命名空间。 也能用同样的方式自动加载。 一个 Enum 定义了一种新的类型,它有固定、数量有限、可能的合法值。

<?php
enum Suit
{
    case Hearts;
    case Diamonds;
    case Clubs;
    case Spades;
}
function pick_a_card(Suit $suit) { ... }

$val = Suit::Diamonds;

// OK
pick_a_card($val);
// OK
pick_a_card(Suit::Clubs);
// TypeError: pick_a_card(): Argument #1 ($suit) must be of type Suit, string given
pick_a_card('Spades');
  • 只读属性

只读属性不能在初始化后更改,即在为它们分配值后。它们可以用于对值对象和数据传输对象建模。

<?php
class BlogData
{
    public readonly Status $status;
  
    public function __construct(Status $status)
    {
        $this->status = $status;
    }
}
  • First-class 可调用语法

现在可以获得对任何函数的引用。这统称为 First-class 可调用语法。

<?php
$foo = $this->foo(...);

$fn = strlen(...);
var_dump($fn('22222')); // 5
  • 新的初始化器

对象现在可以用作默认参数值、静态变量和全局常量,以及属性参数。

<?php
class Service
{
    private Logger $logger;
   
    public function __construct(
        Logger $logger = new NullLogger(),
    ) {
        $this->logger = $logger;
    }
}
  • 纯交集类型

当一个值需要同时满足多个类型约束时,使用交集类型。注意,目前无法将交集和联合类型混合在一起,例如 A&B|C。

<?php
function count_and_iterate(Iterator&Countable $value) {
    foreach ($value as $val) {
        echo $val;
    }

    count($value);
}
  • Never 返回类型

使用 never 类型声明的函数或方法表示它不会返回值,并且会抛出异常或通过调用 die()、exit()、trigger_error() 或类似的东西来结束脚本的执行。

<?php
function redirect(string $uri): never {
    header('Location: ' . $uri);
    exit();
}

function redirectToLoginPage(): never {
    redirect('/login');
    echo 'Hello'; // <- dead code detected by static analysis
}
  • Final 类常量

可以声明 final 类常量,以禁止它们在子类中被重写。

<?php
class Foo
{
    final public const XX = "foo";
}

class Bar extends Foo
{
    public const XX = "bar"; // Fatal error
}
  • 纤程

Fibers 是用于实现轻量级协作并发的基础类型。它们是一种创建可以像生成器一样暂停和恢复的代码块的方法,但可以从堆栈中的任何位置进行。Fibers 本身并没有提供并发性,仍然需要一个事件循环。但是,它们允许通过阻塞和非阻塞实现共享相同的 API。。

<?php
$fiber = new Fiber(function (): void {
    $value = Fiber::suspend('fiber');
    echo "Value used to resume fiber: ", $value, PHP_EOL;
});

$value = $fiber->start();

echo "Value from fiber suspending: ", $value, PHP_EOL;

$fiber->resume('test');
// Value from fiber suspending: fiber
// Value used to resume fiber: test
  • 对字符串键控数组的数组解包支持

PHP 以前支持通过扩展运算符在数组内部解包,但前提是数组具有整数键。现在也可以使用字符串键解包数组。

<?php
$arrayA = ['a' => 1];
$arrayB = ['b' => 2];

$result = ['a' => 0, ...$arrayA, ...$arrayB];

// ['a' => 1, 'b' => 2]

▲ 回顶部