0%

浅谈PHP8中的类型定义以及几个新特性

随着PHP8的发布,作为动态类型语言的PHP也有了更大的进步。
此处浅谈一下PHP8中的类型定义以及几个新特性
本文仅介绍重点,详细内容可以参考 PHP 官方

数据类型 (Data Type)

数据类型 (Data Type) 用来表示储存的数据类型,也称为型别。

数据类型说明数据范例
bool布尔true, false
int整型1, 0, -1, …
float浮点数0.1, -0.2, …
string字符串“hello world!”
array数组[“hello”, “world”, 2, 0.1]
object对象new Example(), (object) [‘hello’ => ‘world’]
resource资源资源
null空值null

Function

语法:(PHP7.0以上)

1
2
3
4
function FUNCTION_NAME(VAR_TYPE $VAR_NAME = VAR_DEFAULT_VALUE, ...): RETURN_TYPE{
//do somethings
return $VAR;
}
  • FUNCTION_NAME:函数名
  • VAR_TYPE: 自变量
  • VAR_NAME: 自变量名称
  • VAR_DEFAULT_VALUE: 自变量默认值,此自变量可以不被传入,不传入时自动采用默认值
  • RETURN_TYPE: 返回值
    • Nullsafe operator:加上 ? 表示可能会传 null
    • 另外,可以使用 |null 或者现有的 ? 表示法来表示包含 nullable 的联合体。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      function myStrValue(string|null $a = 'hello'): ?string {
      return $a;
      }
      echo myStrValue();//hello
      echo myStrValue(null);//
      echo myStrValue('你好');//你好

      function myStrConcat(?string $a = 'hello', string $b = null): string {//默认值为null亦可传null
      return $a . $b;
      }
      echo myStrConcat(); //hello
      echo myStrConcat(null); //
      echo myStrConcat(null, 'world'); //world
      echo myStrConcat('你好', '世界'); //你好世界

补充说明:

  • PHP 属于动态类型程序语言,允许所有变量可以不用带入数据类型,改由系统自动判别。但动态类型程序语言最令人诟病的地方就是过度方便新手开发人员 (可以不理会类型),而苦了 Web Server (需要判别类型),也容易造成开发人员因为类型问题产生的语意BUG。
  • 开发人员预先定义好数据类型,可以有效增加程序运行效率。PHP 7.0 起,允许在 function 内约束自变量类型、返回值类型。PHP8起,允许在 function 内约束复合类型。

范例

  • 范例:没有任何自变量也不回传任何东西

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    /**
    * myFirstFunc
    * @return void
    */
    function myFirstFunc(): void{
    echo 'hellowrold';
    return; //回传 void 时,写 return 的话,后面不可以带返回值。也可以不写 return
    }

    myFirstFunc(); // helloworld
  • 范例:两字符串相加,回传字符串类型,第二个自变量预设 null,表示可以不传入。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /**
    * my string concat
    * @param string $a string A
    * @param string $b string B
    * @return string
    */
    function myStrConcat(string $a, string $b = null): string{
    return $a . $b;
    }

    echo myStrConcat('hello', 'world'); // helloworld
    echo myStrConcat('helloworld'); // helloworld
  • 范例:通过数据库,可能会拿到 null,故返回值需检查 null。

    1
    2
    3
    4
    5
    6
    7
    8
    /**
    * get user
    * @param int $userId user ID
    * @return object|null
    */
    function getUser(int $userId): ?object{
    //do something
    }
  • 范例:复合类型,PHP8后允许自变量、返回值有复合类型。

    1
    2
    3
    4
    5
    6
    7
    8
    /**
    * getUsers
    * @param int|array $userIds user IDs
    * @return array|null
    */
    function getUsers(int|array $userIds): ?array{
    //do something
    }
  • 范例:mixed = array|bool|callable|int|float|null|object|resource|string (PHP中不写类型默认为mixed,例如:function getUsers($userId){}。)
    • 请注意,mixed也可以用作参数或属性类型,而不仅仅是作为返回类型。
    • 另请注意,由于mixed已包含null,因此不允许使其为空(nullable)。以下代码将触发错误:
      1
      2
      3
      4
      // Fatal error: Mixed types cannot be nullable, null is already part of the mixed type.
      function getUsers(mixed $userId): ?mixed {
      //do something
      }

其他

顺带提一下php8中比较喜欢的几个更新

Match表达式

你可以称它为switch表达式的大哥,match可以返回值,不需要break语句,可以组合条件,并且不执行任何类型的强制。
新的 match 类似于 switch,并具有以下功能:

  1. Match 是一个表达式,它可以储存到变量中亦可以直接返回。
  2. Match 分支仅支持单行,它不需要一个 break; 语句。
  3. Match 使用严格比较。
    如下所示:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    $result = match($input) {
    0 => "hello",
    '1', '2', '3' => "world",
    };
    $message = match ($statusCode) {
    200, 300 => null,
    404 => 'not found',
    500 => 'server error',
    default => 'unknow status code'
    }

Throw表达式

throw 从语句更改为表达式,从而有可能在许多新位置引发异常:

1
2
3
4
5
$callable = fn() => throw new Exception();
$triggerError = fn () => throw new MyError();
$foo = $bar['offset'] ?? throw new OffsetDoesNotExist('offset')
$condition || throw new Exception('$condition must be truthy')
&& $condition2 || throw new Exception('$condition2 must be truthy');

用参数名传递参数而不是参数的顺序

1
2
3
4
5
6
7
8
9
10
setcookie(
name: 'test',
expires: time() + 60 * 60 * 2
);

$data = [
'name' => 'test',
'expires' => time() + 60 * 60 * 2
];
setcookie(...$data);

构造器属性提升

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/*
* PHP7
*/
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,
) {}
}

字符串与数字的比较更符合逻辑

1
2
3
4
5
6
7
8
/*
* PHP7
*/
0 == 'foobar' // true
/*
* PHP8
*/
0 == 'foobar' // false

Nullsafe 运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
* 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;

对象获取类名

1
2
$object = new stdClass;
var_dump($object::class); // "stdClass"

static return type

1
2
3
4
5
6
7
class Test {
public function withWhatever($whatever): static {
$clone = clone $this;
$clone->whatever = $whatever;
return $clone;
}
}
bulb