PHP 8.1 现已推出,它附带了新功能和性能改进——最令人兴奋的是新的 JIT 编译器。它最近于 2021 年 11 月 25 日发布。
我将详细演示 PHP 8.1 提供的 10 大特性,以便您可以开始在您的项目中使用它们,并改善您的 PHP 体验。初学者和有经验的开发人员可以从本文中受益。
PHP 8.1 提供的 10 大功能
- 枚举
- Fiber(纤维)
never
返回类型readonly
属性final
类常量- 新的
array_is_list()
函数 - 新的
fsync()
和fdatasync()
函数 - 对字符串键数组解包的支持
$_FILES
新的用于目录上传的full_path
键- 新的
IntlDatePatternGenerator
类
1. 枚举
PHP 8.1 添加了对枚举的支持,简写为 enum
。它是一种逐项类型,包含固定数量的可能值。请参阅以下代码片段以了解如何使用枚举。
/** | |
* Declare an enumeration. | |
* It can also contain an optional 'string' or 'int' value. This is called backed Enum. | |
* Backed enums (if used) should match the following criteria: | |
* - Declare the scalar type, whether string or int, in the Enum declaration. | |
* - All cases have values. | |
* - All cases contain the same scalar type, whether string or int. | |
* - Each case has a unique value. | |
*/ | |
enum UserRole: string { | |
case ADMIN = '1'; | |
case GUEST = '2'; | |
case WRITER = '3'; | |
case EDITOR = '4'; | |
} | |
/** | |
* You can access a case by using | |
* the '::' scope resolution operator. | |
* And, to get the name of the enum case, you | |
* can use the '->' followed by the attribute 'name'. | |
*/ | |
echo UserRole::WRITER->name; | |
/** | |
* To get the value of the enum case, you can | |
* use the '->' followed by the attribute 'value'. | |
*/ | |
echo UserRole::WRITER->value; | |
2. Fiber(纤维)
PHP 8.1 添加了对 Fiber
的支持,这是一个低级组件,允许在 PHP 中执行并发代码。Fiber 是一个代码块,它包含自己的变量和状态堆栈。这些 Fiber 可以被视为应用程序线程,可以从主程序启动。一旦启动,主程序将无法挂起或终止 Fiber。它只能从 Fiber 代码块内部暂停或终止。在 Fiber 挂起后,控制权再次返回到主程序,它可以从挂起的点继续执行 Fiber。
Fiber 本身不允许同时执行多个 Fiber 或主线程和一个 Fiber。但是,对于 PHP 框架来说,高效管理执行堆栈并允许异步执行是一个巨大的优势。
请参阅以下代码片段以了解如何使用 Fiber。
/** | |
* Initialize the Fiber. | |
*/ | |
$fiber = new Fiber(function(): void { | |
/** | |
* Print some message from inside the Fiber. | |
* Before the Fiber gets suspended. | |
*/ | |
echo "Welcome to Fiber!\n"; | |
/** | |
* Suspend the Fiber. | |
*/ | |
Fiber::suspend(); | |
/** | |
* Print some message from inside the Fiber. | |
* After the Fiber gets resumed. | |
*/ | |
echo "Welcome back to Fiber!\n"; | |
}); | |
/** | |
* Print a message before starting a Fiber. | |
*/ | |
echo "Starting a Fiber\n"; | |
/** | |
* Start the Fiber. | |
*/ | |
$fiber->start(); | |
/** | |
* Fiber has been suspened from the inside. | |
* Print some message, and then resume the Fiber. | |
*/ | |
echo "Fiber has been suspended\n"; | |
echo "Resuming the Fiber\n"; | |
/** | |
* Resume the Fiber. | |
*/ | |
$fiber->resume(); | |
/** | |
* End of the example. | |
*/ | |
echo "Fiber completed execution\n"; | |
3.never
返回类型
PHP 8.1 添加了名为never
的返回类型。该never
类型可用于指示函数将在执行一组指定的任务后终止程序执行。这可以通过抛出异常、调用exit()
或die()
函数来完成。
never
返回类型类似于void
返回类型。但是,void
返回类型在函数完成一组指定的任务后继续执行。
请参阅以下代码片段以了解如何使用 never 返回类型。
/** | |
* Route Class | |
*/ | |
class Route { | |
/** | |
* Constructor of the class | |
* @return void | |
*/ | |
public function __construct() { | |
} | |
/** | |
* Redirect To a Page | |
* This function redirects to an URL specified by the user. | |
* @method redirect() | |
* @param string $url | |
* @param integer $httpCode | |
* @author Tara Prasad Routray <someemailaddress@example.com> | |
* @access public | |
* @return never | |
*/ | |
public static function redirect($url, $httpCode = 301): never { | |
/** | |
* Redirect to the URL specified. | |
*/ | |
header("Location: {$url}", true, $httpCode); | |
die; | |
} | |
} | |
Route::redirect('https://www.google.com'); | |
4.readonly
属性
PHP 8.1 添加了名为readonly
的类属性。已声明为只读的类属性只能初始化一次。里面设置的值不能改变。如果尝试强行更新该值,应用程序将抛出错误。请参阅以下代码片段以了解如何使用只读属性。
/** | |
* User Class | |
*/ | |
class User { | |
/** | |
* Declare a variable with readonly property. | |
* @var $authUserID | |
* @access public | |
*/ | |
public readonly int $authUserID; | |
/** | |
* Constructor of the class. | |
* @param integer $userID | |
* @return void | |
*/ | |
public function __construct($userID) { | |
/** | |
* Change the value of the property as specified. | |
* Updating the value of readonly properties are | |
* allowed only through the constructor. | |
*/ | |
$this->authUserID = $userID; | |
} | |
/** | |
* Update Auth User ID | |
* This function tries to update the readonly property (which is not allowed). | |
* @method updateAuthUserID() | |
* @param integer $userID | |
* @author Tara Prasad Routray <someemailaddress@example.com> | |
* @access public | |
* @return void | |
*/ | |
public function updateAuthUserID($userID) { | |
/** | |
* Change the value of the property as specified. | |
* Executing this function will throw the following error; | |
* PHP Fatal error: Uncaught Error: Cannot modify readonly property User::$authUserID | |
*/ | |
$this->authUserID = $userID; | |
} | |
} | |
/** | |
* Initialize the class and update the value of the readonly property. | |
*/ | |
$user = new User(30); | |
/** | |
* Print the readonly property value. | |
* This will print 30. | |
*/ | |
echo $user->authUserID; | |
/** | |
* Call another function inside the class and try to update the class property. | |
*/ | |
$user->updateAuthUserID(50); | |
/** | |
* Print the readonly property value. | |
*/ | |
echo $user->authUserID; | |
5. final
类常量
PHP 8.1 添加了对名为final
的类常量的支持。最终类常量不能被修改,即使是通过继承,这意味着它们不能被子类扩展或覆盖。
这个标志不能用于私有常量,因为它不能在类之外被访问。声明 final 和 private 常量将导致致命错误。
请参阅以下代码片段以了解如何使用最终标志。
/** | |
* UserRole Class | |
*/ | |
class UserRole { | |
/** | |
* Declare a final class constant with a value. | |
*/ | |
final public const ADMIN = '1'; | |
} | |
/** | |
* User Class extending the UserRole Class | |
*/ | |
class User extends UserRole { | |
/** | |
* Declare another constant with the same name | |
* as of the parent class to override the value. | |
* | |
* Note: Overriding the value will throw the following error: | |
* PHP Fatal error: User::ADMIN cannot override final constant UserRole::ADMIN | |
*/ | |
public const ADMIN = '2'; | |
} | |
6. 新的 array_is_list()
函数
PHP 8.1 添加了名为array_is_list()
的数组函数。它标识指定的数组是否具有从 0 开始的所有连续整数。如果数组是值的语义列表(一个数组,其键从 0 开始,都是整数,并且之间没有间隙),则此函数返回 true。对于空数组,它也返回 true。请参阅以下代码片段以了解如何使用 array_is_list() 函数。
<?php | |
/** | |
* Returns true for empty array. | |
*/ | |
array_is_list([]); | |
/** | |
* Returns true for sequential set of keys. | |
*/ | |
array_is_list([1, 2, 3]); | |
/** | |
* Returns true as the first key is zero, and keys are in sequential order. | |
* It is same as [0 => 'apple', 1 => 2, 2 => 3] | |
*/ | |
array_is_list(['apple', 2, 3]); | |
/** | |
* Returns true as the first key is zero, and keys are in sequential order. | |
* It is same as [0 => 'apple', 1 => 'scissor'] | |
*/ | |
array_is_list(['apple', 'orange']); | |
/** | |
* Returns true as the first key is zero, and keys are in sequential order. | |
* It is same as [0 => 'apple', 1 => 'scissor'] | |
*/ | |
array_is_list([0 => 'apple', 'orange']); | |
/** | |
* Returns true as the first key is zero, and keys are in sequential order. | |
*/ | |
array_is_list([0 => 'rock', 1 => 'scissor']); | |
?> |
键不是从 0 开始的数组,或者键不是整数,或者键是整数但不按顺序出现的数组将评估为 false。
/** | |
* Returns false as the first key does not start from zero. | |
*/ | |
array_is_list([1 => 'apple', 'orange']); | |
/** | |
* Returns false as the first key does not start from zero. | |
*/ | |
array_is_list([1 => 'apple', 0 => 'orange']); | |
/** | |
* Returns false as all keys are not integer. | |
*/ | |
array_is_list([0 => 'apple', 'fruit' => 'orange']); | |
/** | |
* Returns false as the keys are not in sequential order. | |
*/ | |
array_is_list([0 => 'apple', 2 => 'orange']); | |
7. 新的fsync()
和fdatasync()
函数
PHP 8.1 添加了对fsync()
和fdatasync()
函数的支持。两者都与现有fflush()
函数有相似之处,该函数当前用于将缓冲区刷新到操作系统中。然而,fsync()
和fdatasync()
刷新该缓冲区到物理存储。它们之间的唯一区别是该fsync()
函数在同步文件更改时包含元数据,而该fdatasync()
函数不包含元数据。
fsync()
函数将采用文件指针并尝试将更改提交到磁盘。成功时返回 true,失败时返回 false,如果资源不是文件,则会发出警告。fdatasync()
函数的工作方式相同,但速度稍快一些,因为 fsync() 将尝试完全同步文件的数据更改和有关文件的元数据(上次修改时间等),这在技术上是两次磁盘写入。
请参阅以下代码片段以了解如何使用 fsync() 和 fdatasync() 函数。
/** | |
* Declare a variable and assign a filename. | |
*/ | |
$fileName = 'notes.txt'; | |
/** | |
* Create the file with read and write permission. | |
*/ | |
$file = fopen($fileName, 'w+'); | |
/** | |
* Add some text into the file. | |
*/ | |
fwrite($file, 'Paragraph 1'); | |
/** | |
* Add a line break into the file. | |
*/ | |
fwrite($file, "\r\n"); | |
/** | |
* Add some more text into the file. | |
*/ | |
fwrite($file, 'Paragraph 2'); | |
/** | |
* You can use both the fsync() or fdatasync() functions | |
* to commit changs to disk. | |
*/ | |
fsync($file); // or fdatasync($file). | |
/** | |
* Close the open file pointer. | |
*/ | |
fclose($file); | |
8. 对字符串键数组解包的支持
PHP 8.1 添加了对字符串键数组解包的支持。为了解压数组,PHP 使用展开(…)
运算符。PHP 7.4 中引入了这个运算符来合并两个或多个数组,但语法更简洁。但在 PHP 8.1 之前,展开运算符仅支持带数字键的数组。请参阅以下代码片段以了解如何将展开运算符用于字符串键控数组。
/** | |
* Declare an array | |
*/ | |
$fruits1 = ['Jonathan Apples', 'Sapote']; | |
/** | |
* Declare another array | |
*/ | |
$fruits2 = ['Pomelo', 'Jackfruit']; | |
/** | |
* Merge above two arrays using array unpacking. | |
*/ | |
$unpackedFruits = [...$fruits1, ...$fruits2, ...['Red Delicious']]; | |
/** | |
* Print the above unpacked array. | |
* This will print: | |
* array(5) { | |
* [0]=> | |
* string(15) "Jonathan Apples" | |
* [1]=> | |
* string(6) "Sapote" | |
* [2]=> | |
* string(6) "Pomelo" | |
* [3]=> | |
* string(9) "Jackfruit" | |
* [4]=> | |
* string(13) "Red Delicious" | |
* } | |
*/ | |
var_dump($unpackedFruits); | |
9. $_FILES
新的用于目录上传的 full_path
键
PHP 8.1 添加了对$_FILES
全局变量中full_path
新键的支持。在 PHP 8.1 之前,$_FILES
没有存储到服务器的相对路径或确切目录。因此,您无法使用 HTML 文件上传表单上传整个目录。新full_path
键解决了这个问题。它存储相对路径并在服务器上重建确切的目录结构,使目录上传成为可能。请参阅以下代码片段以了解如何将full_path
键与$_FILES
全局变量一起使用。
/** | |
* Check if the user has submitted the form. | |
*/ | |
if ($_SERVER['REQUEST_METHOD'] === 'POST') { | |
/** | |
* Print the $_FILES global variable. This will display the following: | |
* array(1) { | |
* ["myfiles"]=> array(6) { | |
* ["name"]=> array(2) { | |
* [0]=> string(9) "image.png" | |
* [1]=> string(9) "image.png" | |
* } | |
* ["full_path"]=> array(2) { | |
* [0]=> string(25) "folder1/folder2/image.png" | |
* [1]=> string(25) "folder3/folder4/image.png" | |
* } | |
* ["tmp_name"]=> array(2) { | |
* [0]=> string(14) "/tmp/phpV1J3EM" | |
* [1]=> string(14) "/tmp/phpzBmAkT" | |
* } | |
* // ... + error, type, size | |
* } | |
* } | |
*/ | |
var_dump($_FILES); | |
} | |
<form action="" method="POST" enctype="multipart/form-data"> | |
<input name="myfiles[]" type="file" webkitdirectory multiple /> | |
<button type="submit">Submit</button> | |
</form> |
10. 新的IntlDatePatternGenerator
类
PHP 8.1 添加了对新IntlDatePatternGenerator
类的支持。在 PHP 8.1 之前,只能使用IntlDateFormatter
。虽然它支持昨天、今天和明天使用的八种预定义格式,但是这些格式和IntlDatePatternGenerator
不太一样。这个类允许指定日期、月份和时间的格式,并且顺序将由类自动处理。请参阅以下代码片段以了解如何使用 IntlDatePatternGenerator 类。
/** | |
* Define a default date format. | |
*/ | |
$skeleton = "YYYY-MM-dd"; | |
/** | |
* Parse a time string (for today) according to a specified format. | |
*/ | |
$today = \DateTimeImmutable::createFromFormat('Y-m-d', date('Y-m-d')); | |
/** | |
* =========================== | |
* PRINTING DATE IN USA FORMAT | |
* =========================== | |
* Initiate an instance for the IntlDatePatternGenerator class | |
* and provide the locale information. | |
* In the below example, I've used locale: en_US. | |
*/ | |
$intlDatePatternGenerator = new \IntlDatePatternGenerator("en_US"); | |
/** | |
* Get the correct date format for the locale: en_US. | |
* Following function "getBestPattern" will return: | |
* MM/dd/YYYY | |
*/ | |
$enUSDatePattern = $intlDatePatternGenerator->getBestPattern($skeleton); | |
/** | |
* Use the "formatObject" function of IntlDateFormatter to print as per specified pattern. | |
* This will print the following: | |
* Date in en-US: 12/03/2021 | |
*/ | |
echo "Date in en-US: ". \IntlDateFormatter::formatObject($today, $enUSDatePattern, "en_US"). "\n"; | |
/** | |
* ============================= | |
* PRINTING DATE IN INDIA FORMAT | |
* ============================= | |
* Initiate an instance for the IntlDatePatternGenerator class | |
* and provide the locale information. | |
* In the below example, I've used locale: en_IN. | |
*/ | |
$intlDatePatternGenerator = new \IntlDatePatternGenerator("en_IN"); | |
/** | |
* Get the correct date format for the locale: en_IN. | |
* Following function "getBestPattern" will return: | |
* dd/MM/YYYY | |
*/ | |
$enINDatePattern = $intlDatePatternGenerator->getBestPattern($skeleton); | |
/** | |
* Use the "formatObject" function of IntlDateFormatter to print as per specified pattern. | |
* This will print the following: | |
* Date in en-IN: 03/12/2021 | |
*/ | |
echo "Date in en-IN: ". \IntlDateFormatter::formatObject($today, $enINDatePattern, "en_IN"). "\n"; | |
点赞!您已经完成了 PHP 8.1 提供的功能的学习。现在您可以继续并开始在您当前或即将进行的项目中实现上述功能。
原文:levelup.gitconnected.com/top-10-ph...