PHP 8 đã sẵn sàng để tải xuống! Nó được phát hành vào ngày 26 tháng 11 năm 2020. Bạn có thể tải xuống tại đây.
PHP 8 là một phiên bản PHP chính vừa được phát hành, có nghĩa là nó sẽ giới thiệu một số thay đổi đột phá, cũng như nhiều tính năng mới và cải tiến hiệu suất.
Do những thay đổi lớn, có nhiều khả năng bạn sẽ cần thực hiện một số thay đổi trong code của mình để có thể chạy trên PHP 8.
Tuy nhiên, nếu bạn đã cập nhật các bản phát hành mới nhất (Từ PHP 7.*), thì nâng cấp lên PHP 8 không quá khó.
> Bạn đang quan tâm đến PHP?? Tham gia HỌC LẬP TRÌNH PHP ngay nếu bạn là người mới bắt đầu.
Và đừng lo lắng, tất cả những thứ không được dùng nữa đều được liệt kê trong bài đăng này.
Bên cạnh những thay đổi đột phá, PHP 8 cũng mang đến một loạt các tính năng mới như trình biên dịch JIT (JIT Compiler), union types, attributes, v.v.
TÍNH NĂNG MỚI CỦA PHP 8
Union Types
Với bản chất được định kiểu động của PHP, có rất nhiều trường hợp mà kiểu liên hợp (union types) có thể hữu ích.
Các union types là một tập hợp của hai hoặc nhiều kiểu cho biết rằng một trong hai kiểu đó có thể được sử dụng.
public function foo(Foo|Bar $input): int|float;
Lưu ý rằng void
không bao giờ có thể là một phần của union type, vì nó chỉ ra 'không có giá trị trả lại nào cả'.
Hơn nữa, nullable
có thể được viết bằng cách sử dụng |null
, hoặc bằng cách sử dụng ký hiệu ?
:
public function foo(Foo|null $foo): void;
public function bar(?Bar $bar): void;
JIT
Trình biên dịch JIT - Just-in-time Compiler hứa hẹn cải thiện hiệu suất đáng kể, mặc dù không phải lúc nào là ưu tiên hàng đầu của webstie.
Mình đã thực hiện các bài test của riêng mình trên các ứng dụng web ngoài đời thực và có vẻ như JIT không tạo ra nhiều khác biệt.
Nếu bạn muốn biết thêm về những gì JIT có thể làm cho PHP, bạn có thể xem video này:
PHP 7 Vs JIT PoC
> Hãy xem PHP 8 nhanh như thế nào với JIT?
Toán tử nullsafe
Nếu bạn đã quen thuộc với toán tử liên hợp null thì bạn đã quen với những hạn chế của nó: Nó không hoạt động trên các method call.
Thay vào đó, bạn cần kiểm tra trung gian hoặc dựa vào các trình trợ giúp tùy chọn được cung cấp bởi một số framework:
$startDate = $booking->getStartDate();
$dateAsString = $startDate ? $startDate->asDateTimeString() : null;
Với việc bổ sung toán tử nullsafe, bây giờ chúng ta có thể có hành vi giống như toán tử liên hợp null trên các phương thức!
$dateAsString = $booking->getStartDate()?->asDateTimeString();
Đặt tên cho đối số
Các đối số được đặt tên cho phép bạn chuyển các giá trị vào một hàm, bằng cách chỉ định tên giá trị, do đó bạn không phải xem xét thứ tự của chúng và bạn cũng có thể bỏ qua các tham số tùy chọn!
function foo(string $a, string $b, ?string $c = null, ?string $d = null)
{ /* … */ }
foo(
b: 'value b',
a: 'value a',
d: 'value d',
);
Attributes
Các thuộc tính, thường được gọi là chú thích trong các ngôn ngữ khác, cung cấp một cách để thêm dữ liệu meta vào các lớp mà không cần phải phân tích cú pháp docblocks.
Để xem nhanh, đây là một ví dụ về các thuộc tính trông như thế nào, từ RFC:
#[ExampleAttribute]
class Foo
{
#[ExampleAttribute]
public const FOO = 'foo';
#[ExampleAttribute]
public $x;
#[ExampleAttribute]
public function foo(#[ExampleAttribute] $bar) { }
}
#[Attribute]
class ExampleAttribute
{
public $value;
public function __construct($value)
{
$this->value = $value;
}
}
Lưu ý là base Attribute
này từng được gọi là PhpAttribute
trong RFC gốc, nhưng đã được thay đổi bằng RFC khác sau đấy.
Match Expression
Bạn có thể gọi nó là anh cả của biểu thức switch
, match
có thể trả về giá trị, không yêu cầu câu lệnh break, có thể kết hợp các điều kiện, sử dụng so sánh kiểu nghiêm ngặt và không thực hiện bất kỳ kiểu ép buộc nào.
Nó trông giống như sau:
$result = match($input) {
0 => "hello",
'1', '2', '3' => "world",
};
Constructor
RFC bổ sung thêm cú pháp đặc biệt để tạo giá trị các đối tượng hoặc đối tượng truyền dữ liệu. Thay vì chỉ định các thuộc tính của lớp và một hàm tạo cho chúng, PHP giờ có thể kết hợp chúng thành một.
Thay vì làm như thế này:
class Money
{
public Currency $currency;
public int $amount;
public function __construct(
Currency $currency,
int $amount,
) {
$this->currency = $currency;
$this->amount = $amount;
}
}
Bây giờ bạn có thể làm thế này trong PHP 8:
class Money
{
public function __construct(
public Currency $currency,
public int $amount,
) {}
}
Kiểu trả về static
mới
Mặc dù đã có thể tự trả về, nhưng static không phải là kiểu trả về hợp lệ cho đến PHP 8. Với bản chất dynamic type của PHP, đây là một tính năng sẽ hữu ích cho nhiều lập trình viên.
class Foo
{
public function test(): static
{
return new static();
}
}
Kiểu mixed
mới
Kiểu mixed
(hỗn hợp) này có thể khiến nhiều người có cảm xúc lẫn lộn.
Tuy nhiên, có một lập luận rất tốt để giải quyết vấn đề này: Một kiểu bị thiếu có thể có nhiều ý nghĩa trong PHP:
-
Một hàm không trả về gì hoặc null
-
Chúng ta đang mong đợi một trong một số các kiểu
Bởi vì những lý do trên, kiểu mixed
được thêm vào là một điều tốt. Bản thân mixed
có nghĩa là một trong các kiểu sau:
Lưu ý là mixed
cũng có thể được sử dụng như một tham số hoặc kiểu thuộc tính, không chỉ như một kiểu trả về.
Cũng lưu ý rằng vì mixed
đã bao gồm null, nên không được phép làm cho nó có giá trị rỗng. Điều sau sẽ gây ra lỗi:
// Fatal error: Mixed types cannot be nullable,
// null is already part of the mixed type.
function bar(): ?mixed {}
Throw expression
RFC thay đổi throw
từ là một câu lệnh thành một biểu thức, điều này làm cho nó có thể ném ngoại lệ ở nhiều vị trí mới:
$triggerError = fn () => throw new MyError();
$foo = $bar['offset'] ?? throw new OffsetDoesNotExist('offset');
Kế thừa với các phương thức private
Trước đây, PHP đã từng áp dụng các kiểm tra kế thừa giống nhau trên các phương thức public, protected và private.
Nói cách khác: Các phương thức private phải tuân theo các quy tắc giống như các phương thức protected và public. Điều này không có ý nghĩa, vì các phương thức private sẽ không được các lớp con truy cập.
RFC đã thay đổi hành vi đó, để các kiểm tra kế thừa này không được thực hiện trên các phương thức private nữa.
Hơn nữa, việc sử dụng final private function
cũng không có ý nghĩa, vì vậy làm như vậy bây giờ sẽ kích hoạt cảnh báo:
Warning: Private methods cannot be final as they are never overridden by other classes
Weakmap
Được xây dựng dựa trên weakrefs RFC đã được thêm vào trong PHP 7.4, một bản triển khai WeakMap được thêm vào trong PHP 8.
WeakMap
giữ các tham chiếu đến các đối tượng, điều này không ngăn các đối tượng đó bị thu thập rác.
Lấy ví dụ về ORM, chúng thường triển khai các bộ nhớ đệm chứa các tham chiếu đến các lớp thực thể để cải thiện hiệu suất của quan hệ giữa các thực thể. Không thể thu thập các đối tượng thực thể này, miễn là bộ đệm này có tham chiếu đến chúng, ngay cả khi bộ đệm là thứ duy nhất tham chiếu đến chúng.
Nếu lớp bộ nhớ đệm này sử dụng các tham chiếu và map yếu để thay thế, PHP sẽ thu thập các đối tượng này khi không có gì khác tham chiếu đến chúng nữa. Đặc biệt là trong trường hợp ORM, có thể quản lý hàng trăm, nếu không phải hàng nghìn thực thể trong một yêu cầu; weak map có thể cung cấp một cách tốt hơn, thân thiện hơn với tài nguyên để xử lý các đối tượng này.
Dưới đây cho thấy các weak map trông như thế nào, một ví dụ từ RFC:
class Foo
{
private WeakMap $cache;
public function getSomethingWithCaching(object $obj): object
{
return $this->cache[$obj]
??= $this->computeSomethingExpensive($obj);
}
}
Cho phép ::class
trên objects
Một tính năng nhỏ, nhưng hữu ích: Bây giờ bạn có thể sử dụng ::class
trên các đối tượng, thay vì phải sử dụng get_class()
trên chúng. Nó hoạt động giống như get_class()
.
$foo = new Foo();
var_dump($foo::class);
Non-capturing catches
Bất cứ khi nào bạn muốn bắt một ngoại lệ trước PHP 8, bạn phải lưu trữ nó trong một biến, bất kể bạn có sử dụng biến đó hay không. Với non-capturing catches, bạn có thể bỏ qua biến, vì vậy thay vì sử dụng:
try {
// Something goes wrong
} catch (MySpecialException $exception) {
Log::error("Something went wrong");
}
Giờ bạn có thể làm thế này:
try {
// Something goes wrong
} catch (MySpecialException) {
Log::error("Something went wrong");
}
Lưu ý rằng nó bắt buộc phải luôn chỉ định kiểu, bạn không được phép để trống catch
. Nếu bạn muốn bắt tất cả các ngoại lệ và lỗi, bạn có thể sử dụng Throwable
Dấu phảy ở cuối trong dánh sách tham số
Hiện tại, dấu phảy ở cuối danh sách tham số đã được phép trong PHP 8, có nghĩa là bạn có thể làm như sau:
public function(
string $parameterA,
int $parameterB,
Foo $objectfoo, // Dấu phảy ở cuối
) {
// …
}
Tạo đối tượng DateTime từ interface
Bạn đã có thể tạo một đối tượng DateTime
từ một đối tượng DateTimeImmutable
bằng cách sử dụng DateTime::createFromImmutable($ immutableDateTime)
, nhưng cách khác lại khá phức tạp.
Bằng cách thêm DateTime::createFromInterface()
và DatetimeImmutable::createFromInterface()
, bây giờ có một cách tổng quát để chuyển đổi các đối tượng DateTime
và DateTimeImmutable
cho nhau.
DateTime::createFromInterface(DateTimeInterface $other);
DateTimeImmutable::createFromInterface(DateTimeInterface $other);
Interface Stringable
mới
Interface Stringable
có thể được sử dụng để gõ gợi ý bất kỳ thứ gì triển khai __toString()
.
Bất cứ khi nào một lớp triển khai __toString()
, nó sẽ tự động triển khai interface phía sau và không cần phải triển khai thủ công.
class Foo
{
public function __toString(): string
{
return 'foo';
}
}
function bar(string|Stringable $stringable) { /* … */ }
bar(new Foo());
bar('abc');
Hàm str_contains()
mới
Một số người có thể nói rằng nó xuất hiện quá muộn, nhưng cuối cùng chúng ta không phải dựa vào strpos()
nữa để kiểm tra liệu một chuỗi có chứa một chuỗi khác hay không.
Thay vì làm như trước đây:
if (strpos('string with lots of words', 'words') !== false) { /* … */ }
Giờ chúng ta đã có hàm dành riêng:
if (str_contains('string with lots of words', 'words')) { /* … */ }
Hàm str_start_with()
và str_start_end()
mới
Hai chức năng này cũng xuất hiện quá muộn. Bây giờ, chúng đã được thêm vào trong lỗi php.
str_starts_with('haystack', 'hay'); // true
str_ends_with('haystack', 'stack'); // true
Hàm fdiv()
mới
Hàm fdiv()
mới hoạt động tương tự như hàm fmod()
và intdiv()
, cho phép chia cho 0. Thay vì lỗi, bạn sẽ nhận được INF
, -INF
hoặc NAN
, tùy trường hợp.
Hàm get_debug_type() mới
get_debug_type()
trả về kiểu của một biến. Có vẻ như một cái gì đó gettype () sẽ làm gì? get_debug_type()
trả về đầu ra hữu ích hơn cho mảng, chuỗi, lớp ẩn danh và đối tượng.
Ví dụ: gọi gettype()
trên một lớp \Foo\Bar
sẽ trả về object
. Sử dụng get_debug_type()
sẽ trả về tên lớp.
Bạn có thể tìm thấy danh sách đầy đủ về sự khác biệt giữa get_debug_type()
và gettype()
trong RFC.
Hàm get_resource_id()
mới
Resource là các biến đặc biệt trong PHP, đề cập đến các tài nguyên bên ngoài. Một ví dụ là kết nối MySQL, một ví dụ khác là kết nối tệp.
Mỗi một trong những tài nguyên đó được gán một ID, mặc dù trước đây cách duy nhất để biết id đó là chuyển tài nguyên thành int
:
$resourceId = (int) $resource;
PHP 8 thêm hàm get_resource_id()
, làm cho thao tác này rõ ràng hơn và an toàn hơn:
$resourceId = get_resource_id($resource);
Phương thức trừu tượng trong traits
Các traits có thể chỉ định các phương thức trừu tượng mà các lớp sử dụng chúng phải thực hiện.
Tuy nhiên, có một lưu ý: Trước PHP 8, chữ ký của các triển khai phương thức này không được xác thực. Điều này là hợp lệ:
trait Test {
abstract public function test(int $input): int;
}
class UsesTrait
{
use Test;
public function test($input)
{
return $input;
}
}
PHP 8 sẽ thực hiện xác thực chữ ký phương thức thích hợp khi sử dụng một trait và triển khai các phương thức trừu tượng của nó.
Có nghĩa là giờ bạn sẽ cần viết thế này để thay thế:
class UsesTrait
{
use Test;
public function test(int $input): int
{
return $input;
}
}
Triển khai đối tượng của token_get_all()
Hàm token_get_all()
trả về một mảng giá trị. RFC thêm một lớp PhpToken với một phương thức PhpToken::tokenize()
.
Việc triển khai này hoạt động với các đối tượng thay vì các giá trị thuần túy. Nó tiêu tốn ít bộ nhớ hơn và dễ đọc hơn.
Chỉnh sửa cú pháp biến
Từ RFC: 'RFC đã giải quyết một số mâu thuẫn trong cú pháp biến của PHP. RFC này dự định giải quyết một số ít các trường hợp đã bị bỏ qua. '
ext-json luôn có sẵn
Trước đây, có thể biên dịch PHP mà không cần bật tiện ích mở rộng JSON, điều này không còn khả thi nữa. Vì JSON được sử dụng rộng rãi nên tốt nhất là các lập trình viên luôn có thể tin tưởng là nó đã ở đó, thay vì phải đảm bảo tiện ích mở rộng tồn tại.
CÁC THAY ĐỔI ĐỘT PHÁ TRONG PHP 8
Như đã đề cập ở trên: Đây là một bản cập nhật lớn và do đó sẽ có những thay đổi đột phá. Điều tốt nhất bạn cần làm là xem danh sách đầy đủ các thay đổi đột phá tại tài liệu NÂNG CẤP PHP8.
Mặc dù vậy, nhiều thay đổi đột phá này đã không còn được dùng trong các phiên bản 7.* trước đó, vì vậy nếu bạn đã cập nhật trong nhiều năm, thì việc nâng cấp lên PHP 8 sẽ không quá khó.
Nhất quán Type Error
Các hàm do người dùng định nghĩa trong PHP sẽ ném ra TypeError
, nhưng các hàm nội bộ thì không, chúng phát ra cảnh báo và trả về null
. Kể từ PHP 8, hành vi của các hàm nội bộ đã được thực hiện nhất quán.
Phân loại cảnh báo
Rất nhiều lỗi trước đây chỉ kích hoạt cảnh báo hoặc thông báo, đã được chuyển đổi thành lỗi thích hợp. Chi tiết bạn có thể xem tại đây.
Toán tử @ không còn chặn các lỗi nghiêm trọng nữa
Có thể sự thay đổi này có thể làm lộ ra các lỗi đã được ẩn trước PHP 8. Hãy đảm bảo đặt display_errors=Off
trên production server của bạn!
Mức báo cáo lỗi mặc định
Bây giờ là E_ALL
thay thế mọi thứ trừ E_NOTICE
và E_DEPRECATED
. Điều này có nghĩa là nhiều lỗi có thể bật lên mà trước đó đã bị bỏ qua một cách âm thầm, mặc dù có thể đã tồn tại trước PHP 8.
Chế độ lỗi PDO mặc định
Từ RFC: Chế độ lỗi mặc định hiện tại cho PDO là silent. Điều này có nghĩa là khi lỗi SQL xảy ra, không có lỗi hoặc cảnh báo nào có thể được phát ra và không có trường hợp ngoại lệ nào được đưa ra trừ khi nhà phát triển triển khai xử lý lỗi rõ ràng của riêng họ.
RFC thay đổi lỗi mặc định sẽ thay đổi thành PDO::ERRMODE_EXCEPTION
trong PHP 8.
Ưu tiên concatenation
Mặc dù đã không còn được dùng trong PHP 7.4, nhưng thay đổi này hiện đã có hiệu lực. Nếu bạn viết một cái gì đó như thế này:
echo "sum: " . $a + $b;
Trước đây, PHP sẽ diễn giải nó như thế này:
echo ("sum: " . $a) + $b;
Nhưng giờ, PHP 8 sẽ hiểu như thế này:
echo "sum: " . ($a + $b);
Kiểm tra kiểu chặt chẽ hơn cho các toán tử số học và bitwise
Trước PHP 8, có thể áp dụng toán tử số học hoặc toán tử bitwise trên mảng, tài nguyên hoặc đối tượng. Nhưng giờ thì không còn khả thi nữa và sẽ xuất hiện TypeError
:
Namespaced names
PHP được sử dụng để diễn giải từng phần của namespace (phân tách bằng dấu gạch chéo ngược \
) như một chuỗi các token. RFC đã thay đổi hành vi đó, có nghĩa là các tên dành riêng hiện có thể được sử dụng trong namespace.
Saner numeric strings
Hệ thống kiểu của PHP cố gắng thực hiện nhiều điều thông minh khi nó gặp các số trong chuỗi. RFC làm cho hành vi đó nhất quán và rõ ràng hơn.
So sánh Saner string với number
RFC đã khắc phục trường hợp rất lạ trong PHP đó là việc 0 == 'foo'
cho kết quả là true
. Vẫn có một số trường hợp khác giống như trường hợp này và RFC này sẽ sửa chúng.
Thay đổi Reflection
Một số phương thức reflection không được dùng nữa:
-
ReflectionFunction::isDisabled()
-
ReflectionParameter::getClass()
-
ReflectionParameter::isCallable()
Bây giờ bạn nên sử dụng ReflectionType
để nhận thông tin về kiểu của tham số:
$reflectionParameter->getType()->allowsNull();
Nếu kiểu là một kiểu duy nhất, ReflectionParameter::getType()
trả về một thể hiện của ReflectionNamedType
, bạn có thể:
$reflectionParameter->getType()->getName();
$reflectionParameter->getType()->isBuiltin();
Tuy nhiên, nếu kiểu là kiểu liên hợp, bạn sẽ nhận được một thể hiện của ReflectionUnionType
, có thể cung cấp cho bạn một mảng ReflectionNamedType
như sau:
$reflectionParameter->getType()->getTypes();
Kiểm tra xem một kiểu có phải là liên hợp hay không có thể được thực hiện bằng kiểm tra instanceof
:
if ($reflectionParameter->getType() instanceof ReflectionNamedType) {
// It's a single type
}
if ($reflectionParameter->getType() instanceof ReflectionUnionType) {
// It's a union type
}
Tiếp theo, ba chữ ký phương thức của các lớp reflection đã được thay đổi:
ReflectionClass::newInstance($args);
ReflectionFunction::invoke($args);
ReflectionMethod::invoke($object, $args);
Bây giờ đã trở thành:
ReflectionClass::newInstance(...$args);
ReflectionFunction::invoke(...$args);
ReflectionMethod::invoke($object, ...$args);
Hướng dẫn nâng cấp chỉ định rằng nếu bạn mở rộng các lớp này và vẫn muốn hỗ trợ cả PHP 7 và PHP 8, thì làm như sau:
ReflectionClass::newInstance($arg = null, ...$args);
ReflectionFunction::invoke($arg = null, ...$args);
ReflectionMethod::invoke($object, $arg = null, ...$args);
Sắp xếp ổn định
Trước PHP 8, các thuật toán sắp xếp không ổn định. Điều này có nghĩa là thứ tự của các phần tử bằng nhau không được đảm bảo. PHP 8 thay đổi hành vi của tất cả các hàm sắp xếp thành sắp xếp ổn định.
Lỗi nghiêm trọng đối với chữ ký phương thức không tương thích
Từ RFC: Lỗi kế thừa do chữ ký phương thức không tương thích hiện gây ra lỗi nghiêm trọng hoặc cảnh báo tùy thuộc vào nguyên nhân của lỗi và hệ thống phân cấp kế thừa.
Những thay đổi và không dùng nữa
Trong quá trình phát triển PHP 7.*, một số bản không dùng nữa đã được thêm vào, hiện đã được hoàn thiện trong PHP 8, xem chi tiết tại đây:
Túm lại về PHP 8
Có nhiều thay đổi lớn đáng kể và sức mạnh tăng tiến. PHP đang không ngừng thay đổi, PHP core team và cộng đồng PHP vẫn đang nỗ lực từng ngày để làm cho PHP trở nên tốt hơn, đáp ứng nhu cầu trong thời kỳ mới tốt hơn.
Còn chờ gì nữa mà không nâng cấp ngay lên PHP 8!
Brent
---
HỌC VIỆN ĐÀO TẠO CNTT NIIT - ICT HÀ NỘI
Học Lập trình chất lượng cao (Since 2002). Học thực tế + Tuyển dụng ngay!
Đc: Tầng 3, 25T2, N05, Nguyễn Thị Thập, Cầu Giấy, Hà Nội
SĐT: 02435574074 - 0914939543
Email: hello@niithanoi.edu.vn
Fanpage: https://facebook.com/NIIT.ICT/
#niit #niithanoi #niiticthanoi #hoclaptrinh #khoahoclaptrinh #hoclaptrinhjava #hoclaptrinhphp #php #java #python