PHP 8.1 新口味品尝记录 (一)
前言
PHP 官方在 2021年11月25日发布了 PHP 8.1 正式版本, 带来了很多有意思的新语法和修改, 具体可以看官方文档, 今天开始我们来一个个尝试这些新东西.
新语法与特性较多, 将分开多篇讲述, 找了一圈目前没有代码高亮支持 8.1 语法, 以下代码块请耐心查看
枚举类 enum
1. 基础语法
enum OrderStatus
{
case created;
case payed;
case sent;
case finish;
case Finish;
// ... case 不限量, 大小写敏感
}
// enum 与 class, interface, trait 同级, 也就命名不可重复
class OrderStatus {} // PHP Fatal error: Cannot declare class OrderStatus, because the name is already in use
// 静态清单方法 cases()
OrderStatus::cases(); // [OrderStatus::created, OrderStatus::payed, OrderStatus::sent, OrderStatus::finish, OrderStatus::Finish]
function validStatus(OrderStatus $status)
{
var_dump($status);
return true;
}
$r = validStatus(OrderStatus::payed); // enum(OrderStatus::payed)
var_dump($r); // true
validStatus(OrderStatus::foo); // Error : Undefined constant OrderStatus::foo
// 值是一种新数据类型, 枚举类型, 不是字符串, 有属性 name 就是自身名称字符串
OrderStatus::payed == 'payed'; // false
$s1 = OrderStatus::sent;
$s2 = OrderStatus::sent;
$s1 === $s2; // true
OrderStatus::Finish == OrderStatus::finish; // false
echo OrderStatus::finish->name; // finish
2. Backed 枚举
官方翻译回退枚举, 支持标量形式, 转魔术值与魔术字很好用
// 仅能 int 或者 string, 不允许联合 int|string
// 实际为实现了内置接口 BackedEnum interface
enum OrderStatus: int
{
case created = 0;
case payed = 1;
case sent = 2;
case finish = 3;
// from() 和 tryFrom() 为 Backed Enum 保留方法
public static function from() {} // Error: Cannot redeclare OrderStatus::from()
}
var_dump(OrderStatus::created->value); // int(0)
// 标量 value 不影响 cases() 结果
OrderStatus::cases(); // [OrderStatus::created, OrderStatus::payed, OrderStatus::sent, OrderStatus::finish]
// 只读属性, 不允许赋值
OrderStatus::created->value = 1; // PHP Fatal error: Cannot use temporary expression in write context
// from() 和 tryFrom() 方法主要区别是对于不存在的 value 处理
OrderStatus::from(1); // enum(OrderStatus::payed)
OrderStatus::from(-1); // ValueError: -1 is not a valid backing value for enum "OrderStatus"
OrderStatus::tryFrom(1); // enum(OrderStatus::payed)
OrderStatus::tryFrom(-1); // NULL
// 值比对查找遵循弱类型原则, 转换为定义类型再查找
OrderStatus::from(2.0); // enum(OrderStatus::sent)
OrderStatus::from('2.0'); // enum(OrderStatus::sent)
// !!特别注意特殊值的转换问题
OrderStatus::from('');
OrderStatus::from(false); // enum(OrderStatus::created)
OrderStatus::from(true); // enum(OrderStatus::payed)
OrderStatus::from(null); // TypeError: Passing null to parameter #1 ($value) of type string|int is deprecated
OrderStatus::from(''); // TypeError: Argument #1 ($value) must be of type int, string given
3. interface, function, const
枚举允许实现 interface 与定义 function, 回退枚举枚举例子提到实际为实现 BackedEnum interface
interface Status {
public function hadPay(): bool;
public static function getDefault(): static;
}
enum OrderStatus implements Status
{
case created;
case payed;
case sent;
case finish;
public const PAYED = self::payed;
public function hadPay(): bool
{
return match($this) {
OrderStatus::created => false,
OrderStatus::payed, OrderStatus::sent, OrderStatus::finish => true,
};
}
public static function getDefault(): static
{
return OrderStatus::created;
}
private function _func(): bool
{
return false;
}
}
OrderStatus::PAYED; // enum(OrderStatus::payed)
OrderStatus::created->hadPay(); // false
OrderStatus::created->_func(); // Error: Call to private method OrderStatus::_func() from global scope
OrderStatus::getDefault(); // enum(OrderStatus::created)
readonly
1. 基础说明
- 增加 readonly 修饰符定义类成员变量为真正的只读, 只允许在初始化__construct时候赋值
- 之前只读做法是设置成员变量为 private, 但是可以被class 中 function 修改, "假只读"
- 和常量 const 区别是可以初始化时候赋值
2. 示例
class Human {
public readonly string $name; // 设置 readonly
private string $_sex; // 旧版做法
public function __construct(string $name, string $sex)
{
$this->name = $name;
$this->_sex = $sex;
}
public function getName(): string
{
return $this->name;
}
public function setName(string $newName): never
{
$this->name = $newName;
}
public function getSex(): string
{
return $this->_sex;
}
public function setSex(string $newSex): never
{
$this->_sex = $newSex;
}
}
$coder = new Human('hammer', 'man');
echo $coder->name; // hammer
echo $coder->getName(); // hammer
$coder->setName('nobody'); // Error: Cannot modify readonly property Human::$name
echo $coder->getSex(); // man
$coder->setSex('women');
echo $coder->getSex(); // women
总结
本篇主要示范 enum 与 readonly, 更多内容后续推出 (咕咕咕, 一定一定), 新人发文, 欢迎大家提建议, 是否喜欢代码加注释的讲解风格文章
可以看出 PHP 发展趋势是往强类型靠拢, 提供更多更严谨语法, 优化性能与结构, 我们更应拥抱变化, 与时俱进, 终身学习
如有错误或者疑问, 欢迎回复讨论