PHP 8 có gì mới?
Bài viết được sự cho phép của tác giả Phạm Bình
Chào anh em,
PHP đã chính thức phát hành phiên bản 8.0 (26/11/2020), với nhiều cải tiến mới cả về hiệu năng lẫn cũ pháp. Trong bài viết này, chúng ta cùng review các điểm thay đổi có trong PHP 8 nhé.
Trích lời dẫn trên trang chủ PHP.net
PHP 8.0 là một phiên bản cập nhật lớn của PHP. Phiên bản này bao gồm rất nhiều tính năng mới, đồng thời tối ưu cách truyền tham số (có thể đặt tên khi truyền tham số), union types (một biến có thể thuộc một vài kiểu dữ liệu), attributes, constructor, biểu thức match (cú pháp mới, gần giống switch case), toán tử nullsafe (cho phép truy xuất giá trị null một cách an toàn), JIT (trình biên dịch mới, giúp PHP 8 đạt hiệu năng cao), và cải tiến các về type system, xử lý lỗi, và tính nhất quán.
Chúng ta sẽ tìm hiểu lần lượt về các sự thay đổi của PHP 8 so với phiên bản trước lần lượt qua các mục dưới đây.
Xem thêm nhiều việc làm PHP hấp dẫn trên TopDev
I. TRUYỀN THAM SỐ THEO TÊN GỌI – PHP 8
Việc một function có nhiều tham số (với mình là từ 3 tham số trở nên), có thể khiến developer lúng túng khi sử dụng vì không nhớ rõ ý nghĩa của từng tham số, cũng như thứ tự truyền của chúng.
Ví dụ, function mkdir()
(function giúp tạo thư mục) trong PHP có 4 tham số lần lượt là:
$directory
: Bắt buộc, là đường dẫn để tạo thư mục$permissions
: Không bắt buộc, là khả năng truy cập vào thư mục (kiểu 0777, hay 0655), mặc định là 0777.$recursive
: Không bắt buộc, có cho phép tạo thư mục con ngay cả khi thư mục cha không tồn tại (cho phép tạo kiểu đệ quy), mặc định làfalse
.$context
: Không bắt buộc, còn ý nghĩa là gì thì mình cũng chẳng hiểu lắm, chưa bao giờ dùng đến tham số này.
Các vấn đề mà một developer có thể gặp phải khi sử dụng mkdir()
đó là:
- Đôi khi không nhớ rõ thứ tự của 2 tham số
$permissions
và$recursive
, không biết tham số nào được viết trước. - Nếu muốn đổi giá trị của tham số
$recursive
từfalse
thànhtrue
, developer buộc phải truyền cả tham số$permissions
(vì$permissions
đứng trước$recursive
).
Cả hai vấn đề trên đều gây bất tiện khi sử dụng, để khắc phục nó, thì PHP cung cấp cú pháp mới cho phép truyền tham số theo tên gọi:
<?php
// PHP 7.x
mkdir
(
'./hello/world'
, 0777, true);
// PHP 8
mkdir
(recursive: true, directory:
'./hello/world'
);
// Hoặc
mkdir
(
'./hello/world'
, recursive: true);
Lưu ý:
– Đây chỉ là cú pháp mới mà PHP 8 cung cấp để tiện sử dụng hơn khi cần, còn bạn vẫn có thể sử dụng cú pháp cũ bình thường trên phiên bản PHP 8 này.
– Tên tham số bạn không được phép “tự nghĩ ra” mà phải tuân theo tài liệu của PHP. Như trong ví dụ trên, recursive
và directory
là 2 tham số mà mình buộc phải tuân theo tài liệu mà PHP cung cấp.
Để xem “tên chuẩn” các tham số, có 2 cách:
Cách 1: Xem tài liệu chính thức trên trang chủ php.net (lưu ý phải xem trên trang chính thức, các trang khác có thể viết không đúng).
Cách 2: Sử dụng ReflectionFunction
.
<?php
// Muốn xem chi tiết các tham số của function mkdir
$refFunc
=
new
ReflectionFunction(
'mkdir'
);
foreach
(
$refFunc
->getParameters()
as
$param
) {
$param
. PHP_EOL;
}
/* Output
Parameter #0 [ <required> string $directory ]
Parameter #1 [ <optional> int $permissions = 0777 ]
Parameter #2 [ <optional> bool $recursive = false ]
Parameter #3 [ <optional> $context = null ]
*/
Lưu ý siêu quan trọng
Khuyên bạn nên sử dụng Cách 2 là chính xác nhất, Cách 1 không hẳn sẽ chính xác với mọi function. Như function mkdir
trong ví dụ trên, thì tài liệu PHP viết sai 2 tên tham số là pathname
và mode
, đáng lẽ nó phải là directory
và permissions
mới đúng.
II. TỐI GIẢN CÁCH SET THUỘC TÍNH TỪ CONTRUCTOR – PHP 8
Việc khởi tạo giá trị cho thuộc tính trong contructor của PHP 7 thường được viết như sau:
<?php
// PHP 7
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
;
}
}
Nhưng với PHP 8, bạn có thể viết ngắn gọn thành
<?php
// PHP 8
class
Point {
public
function
__construct(
public
float
$x
= 0.0,
public
float
$y
= 0.0,
public
float
$z
= 0.0,
) {}
}
III. UNION TYPES – PHP 8
PHP ngày càng hoàn thiện hơn về độ chặt chẽ của dữ liệu, trong phiên bản PHP 7.4, chúng ta có thể khai báo kiểu dữ liệu cho thuộc tính của lớp, tuy nhiên nó vẫn gặp một vài bất tiện. Nhưng bất tiện này đã khắc phục trong phiên bản 8 với khái niệm Union types – Cho phép một thuộc tính có thể thuộc nhiều kiểu dữ liệu.
<?php
// PHP 7
class
Number {
// Giả sử có một biến $numeber, và ta mong muốn nó ở dạng số
// Số thì có nhiều kiểu, số nguyên, số thập phân.
private
$number
;
// Nhưng hơi buồn
// Chúng ta không thể chỉ ra biến $number chỉ được phép thuộc dạng số với PHP 7
public
function
__construct(
$number
)
{
$this
->number =
$number
;
}
}
// Dẫn đến việc khởi tạo class, ta vẫn có thể truyền string như thường
// Và không gặp một lỗi nào cả
new
Number(
'NaN'
);
// PHP 8
class
Number {
// PHP 8 cho phép bạn khai báo biến $number chỉ được phép thuộc một trong 2 kiểu dữ liệu int hoặc float
// Khắc phục vấn đề của PHP 7 nêu trên
public
function
__construct(
private
int|float
$number
) {}
}
// Nếu dùng thế này, bạn sẽ gặp lỗi
new
Number(
'NaN'
);
IV. NULLSAFE OPERATOR – PHP 8
Nullsafe operator – tạm dịch là Toán tử null an toàn. Cho phép bạn truy cập vào giá trị của một thuộc tính ở giá trị null
mà không bị lỗi.
Ở các phiên bản PHP trước, để chắc chắn trước khi truy cập vào một giá trị, ta thường kiểm tra nó khác null
để tránh lỗi, và nhìn nó có vẻ dài dòng như sau:
<?php
$country
= null;
if
(
$session
!== null) {
$user
=
$session
->user;
if
(
$user
!== null) {
$address
=
$user
->getAddress();
if
(
$address
!== null) {
$country
=
$address
->country;
}
}
}
Nhưng với PHP 8, bạn có thể rút gọn thành:
<?php
$country
=
$session
?->user?->getAddress()?->country;
Khi bất kỳ thuộc tính nào trong “chuỗi” $session?->user?->getAddress()?->country
là null, thì $country
sẽ nhận giá trị là null
và không có lỗi nào xảy ra.
V. BIỂU THỨC MATCH – PHP 8
Một biểu thức mới khá tương đồng với lệnh switch case
được đưa vào trong phiên bản PHP 8 lần này là match
, nhưng có một số điểm khác biệt sau:
match
là một biểu thức, nghĩa là giá trị của nó có thể được trả về, bạn có thể dễ dàng lưu nó vào một biến để xử lý cho tiện.- Mỗi một nhánh của
match
chỉ được xử lý trên một dòng, nghĩa là bạn không cầnbreak
match
so sánh chặt chẽ về kiểu dữ liệu, giống như bạn so sánh sử dụng===
vậy.
Bạn có thể xem ví dụ sau để hiểu rõ hơn:
<?php
// PHP 7
switch
(8.0) {
case
'8.0'
:
$result
=
"Oh no!"
;
break
;
case
8.0:
$result
=
"This is what I expected"
;
break
;
}
echo
$result
;
// Oh no!
// PHP 8
$result
= match (8.0) {
'8.0'
=>
"Oh no!"
,
8.0 =>
"This is what I expected"
,
};
echo
$result
;
// This is what I expected
Lưu ý: match
khá tương đồng với switch case
, nhưng không thể thay thế hẳn switch case
.
VI. TRÌNH BIÊN DỊCH JIT – PHP 8
Hiểu nhanh thì JIT (Just In Time) là một kỹ thuật được PHP tích hợp vào việc biên dịch code PHP thành mã máy, giúp PHP 8 đạt được hiệu năng cao gấp 1,5 – 2 lần so với PHP 7. Nhưng đừng vội mừng, hãy xem biểu đồ dưới đây và mình sẽ giải thích cho bạn hiểu:
Trong biểu đồ trên:
- bench.php, micro_bech.php, N-body, Mandelbrot đều là các bài test trên ứng dụng PHP đơn giản.
- Các bài test còn lại, lần lượt test trên các ứng dụng PHP có độ phức tạp tăng dần.
- Đường màu đen, kẻ dọc ở biểu đồ trên là ngưỡng tối đa khi PHP không sử dụng JIT.
Từ biểu đồ trên, rút ra nhận xét rằng:
Chỉ có ứng dụng PHP đơn giản khi áp dụng JIT mới có hiệu năng cao, còn các ứng dụng PHP phức tạp, sử dụng các framework, cms phổ biến như WordPress, Symfony (Chắc laravel cũng không ngoại lệ) thì sử dụng JIT lại không đem lại nhiều lợi ích. Thậm chí như trường hợp của Symfony khi áp dụng JIT còn làm ứng dụng chạy chậm hơn so với lúc không áp dụng.
Để nói hết về JIT thì bài viết này là chưa đủ, mình sẽ trình bày chi tiết ở một bài viết khác về cách cài đặt, ưu nhược điểm, cũng như phân tích nên dùng JIT trong dự án thực tế hay không.
VII. MỘT SỐ CẬP NHẬT KHÁC TRÊN PHP 8
Một số cập nhật điển hình khác trên PHP 8 như sau:
- Thay vì sử dụng PHPDoc để chú thích, PHP 8 đã cung cấp thêm cấu trúc metadata.
<?php
// PHP 7
class
PostsController
{
/**
* @Route("/api/posts/{id}", methods={"GET"})
*/
public
function
get(
$id
) {
/* ... */
}
}
// PHP 8
class
PostsController
{
#[Route(
"/api/posts/{id}"
, methods: [
"GET"
])]
public
function
get(
$id
) {
/* ... */
}
}
- Toán tử @ vốn để “câm lặng lỗi” không còn được sử dụng ở PHP 8.
<?php
// Khi thêm @ phía trước, nếu function có thực hiện lỗi cũng sẽ không báo lỗi
// Nhưng đó đã là quá khứ rồi.
// Ở PHP 8 vẫn báo lỗi bình thường
@unlink(
'hello/world'
);
- Cụm
try {} catch () {}
có thể không cần biến $exception trong catch.
<?php
// PHP 7
try
{
1/0;
}
catch
(\Exception) {
// Sẽ báo lỗi cú pháp ở dòng này
die
(
'Something wrong'
);
}
// PHP 8
try
{
1/0;
}
catch
(\Exception) {
// Chạy bình thường
die
(
'Something wrong'
);
}
- Cho phép dấu phẩy ở cuối danh sách tham số.
<?php
// PHP 7
class
Uri
{
private
function
__construct(
?string
$scheme
,
?string
$user
,
?string
$pass
,
?string
$host
,
?int
$port
,
string
$path
,
?string
$query
,
?string
$fragment
// <-- Tham số cuối cùng không được phép có dấu phẩy
) {
...
}
}
// PHP 8
class
Uri
{
private
function
__construct(
?string
$scheme
,
?string
$user
,
?string
$pass
,
?string
$host
,
?int
$port
,
string
$path
,
?string
$query
,
?string
$fragment
,
// <-- Được phép viết dấu phẩy ở tham số cuối cùng
) {
...
}
}
- Bổ sung một số function mới str_contains(), str_starts_with(), str_ends_with()
VIII. TỔNG KẾT
Trên là những cập nhật điển hình nhất của PHP 8, và bài viết của mình đã nêu được khoảng 80% những gì PHP cập nhật trong phiên bản lần này. Nếu muốn tìm hiểu chi tiết, bạn có thể đọc từ tài liệu chính thức của PHP.
Xin chào, hẹn gặp lại.
Bài viết gốc được đăng tải tại phambinh.net
Có thể bạn quan tâm:
- PHP 8.0 có những tính năng gì mới?
- PHP 8: match hay là switch?
- Những điểm mới của Java 8 (phần 6: Nashorn engine và lập trình tuần tự)
Truy cập ngay việc làm IT đãi ngộ tốt trên TopDev
- B BenQ RD Series – Dòng Màn Hình Lập Trình 4k+ Đầu Tiên Trên Thế Giới
- F Framework nào tốt nhất cho dự án của bạn? – Checklist chi tiết
- K Kinh nghiệm xử lý responsive table hiệu quả
- S Stackoverflow là gì? Bí kíp tận dụng Stack Overflow hiệu quả
- 7 7 kinh nghiệm hữu ích khi làm việc với GIT trong dự án
- B Bài tập Python từ cơ bản đến nâng cao (có lời giải)
- B Bảo mật API là gì? Một số nguyên tắc và kỹ thuật cần biết
- H Hướng dẫn cài đặt và tự học lập trình Python cơ bản từ A-Z
- C Chinh Phục Phân Tích Dữ Liệu Với Pandas Trong Python: Hướng Dẫn Từng Bước
- D Display CSS là gì? Cách khai báo và sử dụng thuộc tính display trong CSS