PHP 8.1 is out now, and it comes with new features and performance improvements - the most exciting being the new JIT compiler. It was recently published on November 25, 2021.
I'll demonstrate in detail the top 10 features provided by PHP 8.1 so that you can start using them in your projects and improve your PHP experience. Beginners and experienced developers can benefit from this article.
Top 10 features provided by PHP 8.1
- Enumeration
- Fiber
never
return typereadonly
attributefinal
class constants- New
array_is_list()
function - New
fsync()
andfdatasync()
functions - Support for unpacking arrays of string keys
$_FILES
newfull_path
key for directory uploads- The new
IntlDatePatternGenerator
class
1. enumeration
PHP 8.1 added support for enums, abbreviated as enum
. It is an itemized type that contains a fixed number of possible values. See the following code snippet to learn how to use enums.
<?php
/**
* 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 added support for Fiber
, a low-level component that allows concurrent code execution in PHP. A fiber is a block of code that contains its own variable and state stack. These fibers can be viewed as application threads and can be started from the main program. Once started, the main program cannot suspend or terminate Fiber. It can only be paused or terminated from within a Fiber code block. After the fiber is suspended, control is returned to the main program again, which can continue executing the fiber from the point where it was suspended.
Fiber itself does not allow concurrent execution of multiple fibers or the main thread and a fiber. However, it is a huge advantage for a PHP framework to efficiently manage the execution stack and allow asynchronous execution.
See the code snippet below to learn how to use Fiber.
<?php
/**
* 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
return type
PHP 8.1 added a return type called never
. The never
type can be used to indicate that the function will terminate program execution after performing a specified set of tasks. This can be done by throwing an exception, calling the exit()
or die()
functions.
The
never
return type is similar to thevoid
return type. However, thevoid
return type continues execution after the function has completed a specified set of tasks.
See the following code snippet for how to use the never return type.
<?php
/**
* 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
property
PHP 8.1 added a class attribute called readonly
. A class property that has been declared read-only can only be initialized once. The value set inside cannot be changed. If you try to force update the value, the application will throw an error. See the following code snippet for how to use read-only properties.
<?php
/**
* 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 anotherfunction inside the class and try to update the class property.
*/
$user->updateAuthUserID(50);
/**
* Print the readonly property value.
*/
echo $user->authUserID;
?>
5. final
class constants
PHP 8.1 added support for class constants named final
. Final class constants cannot be modified, even through inheritance, which means they cannot be extended or overridden by subclasses.
This flag cannot be used for private constants because it cannot be accessed outside the class. Declaring final and private constants will result in a fatal error.
See the following code snippet for how to use the final flag.
<?php
/**
* 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. New array_is_list()
function
PHP 8.1 added an array function called array_is_list()
. It identifies whether the specified array has all consecutive integers starting at 0. This function returns true if the array is a semantic list of values (an array whose keys start at 0, are integers, and have no gaps in between). It also returns true for empty arrays. See the following code snippet for how to use the array_is_list() function.
<?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 the 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']);
?>
An array whose keys are not 0-based, or whose keys are not integers, or whose keys are integers but not in order will evaluate to false.
<?php
/**
* 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. New fsync()
and fdatasync()
functions
PHP 8.1 added support for the fsync()
and fdatasync()
functions. Both share similarities with the existing fflush()
function, which is currently used to flush buffers into the operating system. However, fsync()
and fdatasync()
flush the buffer to physical storage. The only difference between them is that the fsync()
function includes metadata when synchronizing file changes, while the fdatasync()
function does not.
The
fsync()
function will take the file pointer and try to commit the changes to disk. Returns true on success, false on failure, and warns if the resource is not a file. Thefdatasync()
function works the same way, but is slightly faster because fsync() will try to fully synchronize the file's data changes and metadata about the file (last modified time, etc.), which is technically twice disk write.
See the following code snippets to learn how to use the fsync() and fdatasync() functions.
<?php
/**
* 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 changes to disk.
*/
fsync($file); // or fdatasync($file).
/**
* Close the open file pointer.
*/
fclose($file);
?>
8. Support for unpacking arrays of string keys
PHP 8.1 added support for unpacking arrays of string keys. To unpack arrays, PHP uses the spread (…)
operator. This operator was introduced in PHP 7.4 to combine two or more arrays, but with a cleaner syntax. But before PHP 8.1, the spread operator only supported arrays with numeric keys. See the following code snippet to learn how to use the spread operator with string keyed arrays.
<?php
/**
* 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
new full_path
key for directory uploads
PHP 8.1 added support for the new key full_path
in the $_FILES
global variable. Before PHP 8.1, $_FILES
did not store a relative path or exact directory to the server. Therefore, you cannot upload an entire catalog using the HTML file upload form. The new full_path
key solves this problem. It stores relative paths and rebuilds the exact directory structure on the server, making directory uploads possible. See the following code snippet for how to use the full_path
key with the $_FILES
global variable.
<?php
/**
* 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. New IntlDatePatternGenerator
class
PHP 8.1 added support for the new IntlDatePatternGenerator
class. Before PHP 8.1, only IntlDateFormatter
could be used. Although it supports eight predefined formats used yesterday, today and tomorrow, these formats are not the same as IntlDatePatternGenerator
. This class allows to specify the format of the date, month and time, and the ordering will be handled automatically by the class. See the following code snippet to learn how to use the IntlDatePatternGenerator class.
<?php
/**
* 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";
?>
Post comment 取消回复