Sự khác biệt giữa PHP 7 và 8

Để ý. Trong vài tháng tới, chúng tôi sẽ tổ chức lại trang web tài liệu App Engine để giúp tìm nội dung dễ dàng hơn và phù hợp hơn với các sản phẩm còn lại của Google Cloud. Nội dung tương tự sẽ khả dụng nhưng điều hướng hiện sẽ khớp với phần còn lại của các sản phẩm Đám mây. Nếu bạn có phản hồi hoặc câu hỏi khi điều hướng trang web, hãy nhấp vào Gửi phản hồi

  • Trang chủ
  • Tài liệu
  • Ứng dụng động cơ
  • Tài liệu
  • Môi trường tiêu chuẩn

Gửi phản hồiSự khác biệt giữa PHP 5. 5 và PHP 7/8 Sắp xếp ngăn nắp với các bộ sưu tập Lưu và phân loại nội dung dựa trên sở thích của bạn

Trang này trình bày cách di chuyển PHP 5 của bạn. 5 vào thời gian chạy PHP 7/8 trên môi trường tiêu chuẩn của Máy ứng dụng

Vấn đề tương thích giữa PHP 5. 5 và PHP 7/8

Tài liệu PHP chính thức cung cấp thông tin về việc di chuyển từ các phiên bản PHP khác nhau

  • Di chuyển từ PHP 5. 5. x sang PHP5. 6. x
  • Di chuyển từ PHP 5. 6. x sang PHP 7. 0. x
  • Di chuyển từ PHP 7. 0. x sang PHP 7. 1. x
  • Di chuyển từ PHP 7. 1. x sang PHP 7. 2. x
  • Di chuyển từ PHP 7. 2. x sang PHP 7. 3. x
  • Di chuyển từ PHP 7. 3. x sang PHP 7. 4. x
  • Di chuyển từ PHP 7. 4. x sang PHP 8. 0. x
  • Di chuyển từ PHP 8. 0. x sang PHP 8. 1. x

Di chuyển tệp app.yaml của bạn

Bạn phải đặt bộ điều khiển phía trước để xử lý tất cả định tuyến trong ứng dụng của mình. Để biết thêm thông tin, xem

Thời gian chạy PHP 7/8 không cho phép tùy chỉnh phần tử trình xử lý script. Giá trị hợp lệ duy nhất là auto, bởi vì tất cả lưu lượng truy cập được phục vụ bằng cách sử dụng lệnh điểm vào. Tất cả các trình xử lý URL không tĩnh phải bao gồm script: auto để triển khai thành công

Hành vi của một số phần tử trong tệp cấu hình app.yaml đã được sửa đổi

ElementChange typeDescription_______156_______AddedTùy chọn, sử dụng trường này để. threadsafeKhông dùng nữaTất cả các ứng dụng được coi là an toàn theo luồng, nghĩa là một phiên bản có thể xử lý nhiều yêu cầu cùng một lúc. api_versionKhông dùng nữaĐược yêu cầu trước đây nhưng không cần thiết trong thời gian chạy PHP 7/8. application_readableKhông dùng nữa_______151_______0Không dùng nữa_______151_______1Không dùng nữa Các phụ thuộc bên thứ ba tùy ý có thể được cài đặt bằng tệp siêu dữ liệu app.yaml2. app.yaml3Sửa đổi
  • Trường script là tùy chọn và giá trị duy nhất được chấp nhận là auto. Sử dụng khung web (như app.yaml6, app.yaml7, app.yaml8 hoặc một tùy chọn tương tự) với định tuyến trong ứng dụng để thực thi tập lệnh khi yêu cầu chạm vào một tuyến cụ thể
  • Trường app.yaml9 không được hỗ trợ. Sử dụng Quản lý danh tính và truy cập (IAM) để quản lý người dùng

Nếu bạn sử dụng bất kỳ trường nào không được dùng nữa, sẽ có lỗi khi triển khai ứng dụng

Để biết thêm thông tin, hãy xem tài liệu tham khảo app.yaml

Giảm giới hạn thời gian chạy

Thời gian chạy PHP 7/8 có ít hạn chế hơn so với PHP 5. 5 thời gian chạy

  • Cài đặt phụ thuộc của bên thứ ba
  • Thời gian chạy bao gồm một
  • Tạo các luồng hoặc quy trình nền nằm ngoài phạm vi của yêu cầu trong khi phiên bản chạy
  • Sử dụng để tích hợp ứng dụng với các dịch vụ Google Cloud khác. Để biết thêm thông tin, hãy xem trang Cài đặt thư viện máy khách Google Cloud

Để biết thêm thông tin, hãy xem tài liệu môi trường thời gian chạy PHP 7/8

Di chuyển từ App Engine PHP SDK

Để giảm bớt sự phức tạp và nỗ lực di chuyển trong thời gian chạy, môi trường tiêu chuẩn của Máy ứng dụng cho phép bạn truy cập nhiều API và dịch vụ đi kèm cũ trong thời gian chạy PHP 7/8, chẳng hạn như Memcache. Ứng dụng PHP 7/8 của bạn có thể gọi các API dịch vụ đi kèm thông qua SDK máy ứng dụng dành cho PHP 7/8 và truy cập hầu hết các chức năng giống như trên thời gian chạy PHP 5. Không phải tất cả các dịch vụ đi kèm kế thừa có sẵn cho PHP 5 đều có dịch vụ tương ứng trong PHP 7/8. Để biết danh sách đầy đủ các API dịch vụ đi kèm cũ có sẵn cho PHP 7/8, hãy xem tài liệu tham khảo API dịch vụ đi kèm cũ

Bạn cũng có tùy chọn sử dụng các sản phẩm Google Cloud cung cấp chức năng tương tự như các dịch vụ đi kèm cũ. Các sản phẩm Google Cloud này cung cấp thư viện ứng dụng khách Google Cloud CLI đặc trưng. Đối với các dịch vụ đi kèm cũ không có sẵn dưới dạng các sản phẩm riêng biệt trong Google Cloud, chẳng hạn như dịch vụ tìm kiếm, bạn có thể sử dụng các nhà cung cấp bên thứ ba hoặc các giải pháp thay thế khác. Để tìm hiểu thêm về việc di chuyển sang các dịch vụ không theo nhóm, hãy xem Di chuyển từ các dịch vụ theo nhóm

Bản cập nhật lớn mới này mang lại nhiều tối ưu hóa và các tính năng mạnh mẽ cho ngôn ngữ. Chúng tôi rất vui khi được hướng dẫn bạn những thay đổi thú vị nhất sẽ cho phép chúng tôi viết mã tốt hơn và xây dựng các ứng dụng mạnh mẽ hơn

Sự khác biệt giữa PHP 7 và 8
PHP8. 0 Phụ lục thông báo

Bạn đã sẵn sàng chưa?

PHP JIT (Trình biên dịch đúng lúc)

Tính năng được hoan nghênh nhất đi kèm với PHP 8 là trình biên dịch Just-in-time (JIT). JIT là gì?

Đề xuất RFC mô tả JIT như sau

“PHP JIT được triển khai như một phần gần như độc lập của OPcache. Nó có thể được bật/tắt tại thời điểm biên dịch PHP và tại thời điểm chạy. Khi được bật, mã gốc của các tệp PHP được lưu trữ trong một vùng bổ sung của bộ nhớ dùng chung OPcache và op_array→opcodes[]. (các) trình xử lý giữ con trỏ tới các điểm nhập của mã JIT-ed. ”

Vì vậy, làm thế nào chúng ta có được JIT, và sự khác biệt giữa JIT so với OPcache là gì?

Kinsta chiều chuộng tôi đến mức bây giờ tôi yêu cầu mức độ dịch vụ đó từ mọi nhà cung cấp. Chúng tôi cũng cố gắng đạt được mức đó với sự hỗ trợ của công cụ SaaS

Sự khác biệt giữa PHP 7 và 8
Suganthan Mohanadasan từ @Suganthanmn
Xem kế hoạch

Để hiểu rõ hơn JIT là gì đối với PHP, chúng ta hãy xem nhanh cách PHP thực thi mã nguồn cho đến kết quả cuối cùng

Việc thực thi PHP là một quá trình gồm 4 giai đoạn

  • Lexing/Tokenizing. Đầu tiên, trình thông dịch đọc mã PHP và xây dựng một bộ mã thông báo
  • phân tích cú pháp. Trình thông dịch kiểm tra xem tập lệnh có khớp với quy tắc cú pháp hay không và sử dụng mã thông báo để xây dựng Cây cú pháp trừu tượng (AST), một biểu diễn phân cấp cấu trúc của mã nguồn
  • biên soạn. Trình thông dịch duyệt qua cây và dịch các nút AST thành mã lệnh Zend cấp thấp, là mã định danh số xác định loại lệnh được thực hiện bởi Zend VM
  • Diễn dịch. Opcodes được giải thích và chạy trên Zend VM

Hình ảnh sau đây cho thấy một đại diện trực quan của quá trình thực thi PHP cơ bản

Sự khác biệt giữa PHP 7 và 8
Quy trình thực thi PHP cơ bản

Vậy OPcache làm cho PHP nhanh hơn như thế nào?

Tiện ích mở rộng OPcache

PHP là ngôn ngữ thông dịch. Điều này có nghĩa là, khi một tập lệnh PHP chạy, trình thông dịch sẽ phân tích cú pháp, biên dịch và thực thi mã lặp đi lặp lại trên mỗi yêu cầu. Điều này có thể dẫn đến và thêm thời gian

Đây là nơi tiện ích mở rộng OPcache phát huy tác dụng

“OPcache cải thiện hiệu suất PHP bằng cách lưu trữ mã byte của tập lệnh được biên dịch sẵn trong bộ nhớ dùng chung, do đó loại bỏ nhu cầu PHP tải và phân tích cú pháp tập lệnh trên mỗi yêu cầu. ”

Khi bật OPcache, trình thông dịch PHP chỉ trải qua quy trình 4 giai đoạn được đề cập ở trên khi tập lệnh chạy lần đầu tiên. Vì mã byte PHP được lưu trữ trong bộ nhớ dùng chung, nên chúng có sẵn ngay lập tức dưới dạng biểu diễn trung gian cấp thấp và có thể được thực thi ngay trên Zend VM

Sự khác biệt giữa PHP 7 và 8
Quy trình thực thi PHP có bật OPcache

Kể từ PHP 5. 5, tiện ích mở rộng Zend OPcache có sẵn theo mặc định và bạn có thể kiểm tra xem mình đã định cấu hình đúng tiện ích này hay chưa bằng cách gọi

class Test {
    // Error: Using null default on non-nullable property
    public function __construct(public Type $prop = null) {}

    // Correct: Make the type explicitly nullable instead
    public function __construct(public ?Type $prop = null) {}
}
7 từ tập lệnh trên máy chủ của bạn hoặc kiểm tra tệp php của bạn. ini (xem cài đặt cấu hình OPcache)

Cách đọc được đề nghị. Cách cải thiện giới hạn bộ nhớ PHP trong WordPress

Sự khác biệt giữa PHP 7 và 8
Phần Zend OPcache trong trang phpinfo

tải trước

OPcache gần đây đã được cải tiến với việc triển khai tính năng tải trước, một tính năng OPcache mới được bổ sung với PHP 7. 4. Tải trước cung cấp một cách để lưu trữ một tập lệnh được chỉ định vào bộ nhớ OPcache “trước khi bất kỳ mã ứng dụng nào được chạy. ” Tuy nhiên, nó không mang lại sự cải thiện rõ rệt về hiệu suất cho các ứng dụng dựa trên web điển hình

Bạn có thể đọc thêm về tải trước trong

Với JIT, PHP tiến thêm một bước

JIT — Trình biên dịch đúng lúc

Ngay cả khi opcode là biểu diễn trung gian cấp thấp, chúng vẫn phải được biên dịch thành mã máy. JIT “không giới thiệu bất kỳ biểu mẫu IR (Biểu diễn trung gian) bổ sung nào”, nhưng sử dụng DynASM (Trình biên dịch động cho các công cụ tạo mã) để tạo mã gốc trực tiếp từ mã byte PHP

Nói tóm lại, JIT dịch các phần nóng của mã trung gian thành mã máy. Bỏ qua quá trình biên dịch, nó có thể mang lại những cải tiến đáng kể về hiệu suất và mức sử dụng bộ nhớ

Zeev Surasky, đồng tác giả của đề xuất PHP JIT, cho thấy mức độ tính toán sẽ nhanh hơn với JIT

Nhưng liệu JIT có cải thiện hiệu suất WordPress một cách hiệu quả không?

JIT cho các ứng dụng web trực tiếp

Theo JIT RFC, việc triển khai trình biên dịch kịp thời sẽ cải thiện hiệu suất PHP. Nhưng liệu chúng ta có thực sự trải nghiệm những cải tiến như vậy trong các ứng dụng thực tế như WordPress không?

Các thử nghiệm ban đầu cho thấy JIT sẽ giúp khối lượng công việc sử dụng nhiều CPU chạy nhanh hơn đáng kể.

“… giống như những lần thử trước – hiện tại nó dường như không cải thiện đáng kể các ứng dụng thực tế như WordPress (với opcache. jit=1235 326 yêu cầu/giây so với 315 yêu cầu/giây)

Nó được lên kế hoạch cung cấp thêm nỗ lực, cải thiện JIT cho các ứng dụng thực tế, sử dụng tối ưu hóa hồ sơ và đầu cơ. ”

Khi bật JIT, mã sẽ không được chạy bởi Zend VM mà bởi chính CPU, điều này sẽ cải thiện tốc độ tính toán. Các ứng dụng web như WordPress cũng dựa vào các yếu tố khác như TTFB, tối ưu hóa cơ sở dữ liệu, yêu cầu HTTP, v.v.

Sự khác biệt giữa PHP 7 và 8
Đóng góp JIT tương đối vào hiệu suất PHP 8 (Nguồn hình ảnh. PHP8. 0 Phụ lục Thông báo)

Vì vậy, chúng ta không nên mong đợi một sự gia tăng đáng kể về tốc độ thực thi PHP khi nói đến WordPress và các ứng dụng tương tự. Tuy nhiên, JIT có thể mang lại một số lợi ích cho các nhà phát triển

:

“Lợi ích của trình biên dịch JIT là đại khái (và như đã được nêu trong RFC)

  • Hiệu suất tốt hơn đáng kể cho mã số
  • Hiệu suất tốt hơn một chút đối với mã ứng dụng web PHP “điển hình”
  • Khả năng chuyển nhiều mã hơn từ C sang PHP, bởi vì PHP bây giờ sẽ đủ nhanh. ”

Vì vậy, mặc dù JIT sẽ khó mang lại những cải tiến lớn cho hiệu suất của WordPress, nhưng nó sẽ nâng cấp PHP lên cấp độ tiếp theo, biến nó thành ngôn ngữ mà nhiều chức năng hiện có thể được viết trực tiếp bằng

Nhược điểm sẽ là độ phức tạp lớn hơn có thể làm tăng chi phí bảo trì, ổn định và gỡ lỗi. Theo Dmitri Stogov

“JIT cực kỳ đơn giản, nhưng dù sao thì nó cũng làm tăng mức độ phức tạp của toàn bộ PHP, nguy cơ xuất hiện các loại lỗi mới và chi phí phát triển và bảo trì. ”

Đề xuất đưa JIT vào PHP 8 được thông qua với 50 phiếu chống 2 phiếu

PHP 8 đã có tại đây. 🚀 Hãy xem phần tìm hiểu sâu của chúng tôi về các tính năng mới. Nhấp để Tweet

Cải tiến PHP 8 và các tính năng mới

Ngoài JIT, chúng ta có thể mong đợi nhiều tính năng và cải tiến với PHP 8. Danh sách sau đây là lựa chọn cẩn thận của chúng tôi về các bổ sung và thay đổi sắp tới sẽ làm cho PHP trở nên đáng tin cậy và hiệu quả hơn

Khuyến mãi bất động sản xây dựng

Là kết quả của một cuộc thảo luận đang diễn ra về việc cải thiện công thái học của đối tượng trong PHP, RFC Quảng cáo Thuộc tính Trình xây dựng đề xuất một cú pháp mới và ngắn gọn hơn sẽ đơn giản hóa việc khai báo thuộc tính, làm cho nó ngắn hơn và ít thừa hơn

Đề xuất này chỉ liên quan đến các tham số được thăng cấp, tôi. e. các tham số phương thức đó có tiền tố là các từ khóa hiển thị công khai, được bảo vệ và riêng tư

Hiện tại, tất cả các thuộc tính phải được lặp lại nhiều lần (ít nhất bốn lần) trước khi chúng ta có thể sử dụng chúng với các đối tượng. Xem xét ví dụ sau từ RFC

class Point {
    public int $x;
    public int $y;
    public int $z;

    public function __construct(
        int $x = 0,
        int $y = 0,
        int $z = 0,
    ) {
        $this->x = $x;
        $this->y = $y;
        $this->z = $z;
    }
}

Theo Nikita Popov, tác giả RFC, chúng ta phải viết tên thuộc tính ít nhất bốn lần ở ba vị trí khác nhau. khai báo thuộc tính, tham số hàm tạo và gán thuộc tính. Cú pháp này đặc biệt không sử dụng được, đặc biệt là trong các lớp có nhiều thuộc tính và nhiều tên mô tả hơn

RFC này đề xuất hợp nhất hàm tạo và định nghĩa tham số. Vì vậy, kể từ PHP 8, chúng ta có một cách khai báo tham số dễ sử dụng hơn. Mã nhìn thấy ở trên có thể thay đổi như hình dưới đây

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}

Và đó là nó. Vì vậy, chúng tôi có một cách mới để quảng cáo các thuộc tính ngắn hơn, dễ đọc hơn và ít bị lỗi hơn. Theo Nikita

Đó là một phép biến đổi cú pháp đơn giản mà chúng tôi đang thực hiện. Nhưng điều đó làm giảm số lượng mã soạn sẵn mà bạn phải viết cho các đối tượng giá trị nói riêng…

Khai báo thuộc tính được chuyển đổi khi chúng ta khai báo rõ ràng các thuộc tính đó và chúng ta có thể sử dụng Reflection API để xem xét các định nghĩa thuộc tính trước khi thực thi (xem )

Phản xạ (và các cơ chế nội quan khác) sẽ quan sát trạng thái sau khi khử đường. Điều này có nghĩa là các thuộc tính được thăng cấp sẽ xuất hiện giống như các thuộc tính được khai báo rõ ràng và các đối số hàm tạo được thăng cấp sẽ xuất hiện dưới dạng các đối số hàm tạo thông thường

// before desugaring
class Point {
    public function __construct(public int $x = 0) {}
}

// after desugaring
class Point {
    public int $x;

    public function __construct(int $x = 0) {
        $this->x = $x;
    }
}

Di sản

Chúng tôi không có bất kỳ giới hạn nào trong việc sử dụng tính kế thừa kết hợp với các tham số được thăng cấp. Dù sao, không có mối quan hệ cụ thể nào giữa các hàm tạo của lớp cha và lớp con. Theo Nikita

Thông thường, chúng ta nói rằng các phương thức luôn phải tương thích với phương thức cha. […] nhưng quy tắc này không áp dụng cho hàm tạo. Vì vậy, hàm tạo thực sự thuộc về một lớp duy nhất và các hàm tạo giữa lớp cha và lớp con không nhất thiết phải tương thích theo bất kỳ cách nào

Đây là một ví dụ

class Test {
    public function __construct(
        public int $x = 0
    ) {}
}

class Child extends Test {
    public function __construct(
        $x, 
        public int $y = 0,
        public int $z = 0,
    ) {
        parent::__construct($x);
    }
}

Điều gì không được phép với các thuộc tính được quảng cáo

Các thuộc tính được quảng cáo được cho phép trong các hàm tạo và đặc điểm không trừu tượng, nhưng có một số hạn chế đáng được đề cập ở đây

Trình xây dựng trừu tượng

Các thuộc tính được quảng cáo không được phép trong các lớp và giao diện trừu tượng

abstract class Test {
    // Error: Abstract constructor.
    abstract public function __construct(private $x);
}
 
interface Test {
    // Error: Abstract constructor.
    public function __construct(private $x);
}
Nullability

Một trong những ràng buộc đáng chú ý nhất có liên quan đến tính vô hiệu. Trước đây, chúng tôi đã sử dụng một loại không thể vô hiệu hóa một cách rõ ràng. Nhưng với giá trị mặc định null, loại này hoàn toàn có thể vô hiệu hóa. Nhưng với các loại thuộc tính, chúng tôi không có hành vi ngầm định này vì các tham số được thăng cấp yêu cầu khai báo thuộc tính và loại nullable phải được khai báo rõ ràng. Xem ví dụ sau từ RFC

class Test {
    // Error: Using null default on non-nullable property
    public function __construct(public Type $prop = null) {}

    // Correct: Make the type explicitly nullable instead
    public function __construct(public ?Type $prop = null) {}
}
Loại có thể gọi

Vì callable không phải là a , nên chúng tôi không được phép sử dụng loại có thể gọi được trong các thuộc tính được thăng hạng

class Test {
    // Error: Callable type not supported for properties.
    public function __construct(public callable $callback) {}
}
Từ khóa var không được phép

Chỉ có thể sử dụng từ khóa khả năng hiển thị với các tham số được thăng cấp, vì vậy không được phép khai báo các thuộc tính hàm tạo bằng từ khóa

class Test {
    // Error: Using null default on non-nullable property
    public function __construct(public Type $prop = null) {}

    // Correct: Make the type explicitly nullable instead
    public function __construct(public ?Type $prop = null) {}
}
8 (xem ví dụ sau từ RFC)

class Test {
    // Error: "var" keyword is not supported.
    public function __construct(var $prop) {}
}
Không cho phép trùng lặp

Chúng ta có thể kết hợp các thuộc tính được thăng cấp và các thuộc tính rõ ràng trong cùng một lớp, nhưng các thuộc tính không thể được khai báo hai lần

class Test {
    public string $prop;
    public int $explicitProp;

    // Correct
    public function __construct(public int $promotedProp, int $arg) {
        $this->explicitProp = $arg;
    }

    // Error: Redeclaration of property.
    public function __construct(public string $prop) {}
}
Tham số biến thể không được phép

Lý do ở đây là kiểu được khai báo khác với tham số matrixdic, mà thực chất là một mảng

class Test {
    // Error: Variadic parameter.
    public function __construct(public string ...$strings) {}
}

Đọc thêm

Để có cái nhìn cận cảnh hơn về Quảng cáo tài sản xây dựng, hãy nghe cuộc phỏng vấn này với Nikita Popov. Để có cái nhìn tổng quan chuyên sâu về công thái học của đối tượng trong PHP, hãy xem bài đăng này và cuộc phỏng vấn sau đây với Larry Garfield

Xác thực cho các phương thức đặc điểm trừu tượng

Các đặc điểm được định nghĩa là “một cơ chế tái sử dụng mã trong các ngôn ngữ kế thừa đơn lẻ như PHP. ” Thông thường, chúng được sử dụng để khai báo các phương thức có thể được sử dụng trong nhiều lớp

Một đặc điểm cũng có thể chứa các phương thức trừu tượng. Các phương thức này chỉ đơn giản khai báo chữ ký của phương thức, nhưng việc triển khai phương thức phải được thực hiện trong lớp bằng cách sử dụng đặc điểm

Theo ,

“Các đặc điểm hỗ trợ việc sử dụng các phương pháp trừu tượng để áp đặt các yêu cầu đối với lớp thể hiện. ”

Điều này cũng có nghĩa là chữ ký của các phương thức phải khớp. Nói cách khác, loại và số lượng đối số bắt buộc phải giống nhau

Dù sao, , tác giả của RFC, việc xác thực chữ ký hiện chỉ được thi hành đột ngột

  • Nó không được thực thi trong trường hợp phổ biến nhất, trong đó việc triển khai phương thức được cung cấp bởi lớp sử dụng. https. //3v4l. tổ chức/SeVK3
  • Nó được thi hành nếu việc triển khai đến từ một lớp cha. https. //3v4l. org/4VCip
  • Nó được thực thi nếu việc triển khai đến từ một lớp con. https. //3v4l. tổ chức/q7Bq2

Ví dụ sau đây từ Nikita liên quan đến trường hợp đầu tiên (chữ ký không bắt buộc)

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
0

Như đã nói, RFC này đề xuất luôn đưa ra một lỗi nghiêm trọng nếu phương thức triển khai không tương thích với phương thức đặc điểm trừu tượng, bất kể nguồn gốc của nó

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
1

RFC này đã được nhất trí thông qua

Chữ ký phương thức không tương thích

Trong PHP, lỗi kế thừa do chữ ký phương thức không tương thích sẽ 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 gây ra lỗi

Nếu một lớp đang triển khai một giao diện, các chữ ký phương thức không tương thích sẽ gây ra lỗi nghiêm trọng. Theo tài liệu Giao diện đối tượng

“Lớp triển khai giao diện phải sử dụng chữ ký phương thức tương thích với LSP (Nguyên tắc thay thế Liskov). Không làm như vậy sẽ dẫn đến một lỗi nghiêm trọng. ”

Dưới đây là một ví dụ về lỗi thừa kế với giao diện

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
2

Trong PHP7. 4, đoạn mã trên sẽ đưa ra lỗi sau

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
3

Một hàm trong lớp con có chữ ký không tương thích sẽ đưa ra cảnh báo. Xem đoạn mã sau từ RFC

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
4

Trong PHP7. 4, đoạn mã trên sẽ chỉ đưa ra một cảnh báo

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
5

Bây giờ, RFC này đề xuất luôn đưa ra một lỗi nghiêm trọng đối với các chữ ký phương thức không tương thích. Với PHP 8, mã mà chúng ta đã thấy trước đó ở trên sẽ nhắc như sau

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
6

Mảng bắt đầu với một chỉ số tiêu cực

Trong PHP, nếu một mảng bắt đầu bằng một chỉ số âm (_______0_______9), thì các chỉ số sau sẽ bắt đầu từ 0 (thêm về điều này trong tài liệu

class Test {
    // Error: Callable type not supported for properties.
    public function __construct(public callable $callback) {}
}
0). Nhìn vào ví dụ sau

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
7

Trong PHP7. 4 kết quả sẽ như sau

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
8

Bây giờ, RFC này đề xuất thay đổi mọi thứ sao cho chỉ số thứ hai sẽ là

class Test {
    // Error: Callable type not supported for properties.
    public function __construct(public callable $callback) {}
}
1, tùy theo giá trị của
class Test {
    // Error: Callable type not supported for properties.
    public function __construct(public callable $callback) {}
}
2

Trong PHP 8, đoạn mã trên sẽ dẫn đến mảng sau

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
9

Với PHP 8, các mảng bắt đầu bằng chỉ mục âm sẽ thay đổi hành vi của chúng. Đọc thêm về sự không tương thích ngược trong

Liên minh loại 2. 0

Các loại liên kết chấp nhận các giá trị có thể thuộc các loại khác nhau. Hiện tại, PHP không cung cấp hỗ trợ cho các kiểu kết hợp, ngoại trừ cú pháp

class Test {
    // Error: Callable type not supported for properties.
    public function __construct(public callable $callback) {}
}
3 và kiểu đặc biệt
class Test {
    // Error: Callable type not supported for properties.
    public function __construct(public callable $callback) {}
}
4

Trước PHP 8, các loại liên kết chỉ có thể là , như trong ví dụ sau từ RFC

// before desugaring
class Point {
    public function __construct(public int $x = 0) {}
}

// after desugaring
class Point {
    public int $x;

    public function __construct(int $x = 0) {
        $this->x = $x;
    }
}
0

Bây giờ, Liên minh loại 2. 0 RFC đề xuất thêm hỗ trợ cho các loại liên kết trong chữ ký hàm, vì vậy chúng tôi sẽ không dựa vào tài liệu nội tuyến nữa mà thay vào đó sẽ xác định các loại liên kết bằng cú pháp

class Test {
    // Error: Callable type not supported for properties.
    public function __construct(public callable $callback) {}
}
5

// before desugaring
class Point {
    public function __construct(public int $x = 0) {}
}

// after desugaring
class Point {
    public int $x;

    public function __construct(int $x = 0) {
        $this->x = $x;
    }
}
1

Theo giải thích của Nikita Popov trong RFC,

“Việc hỗ trợ các kiểu kết hợp trong ngôn ngữ cho phép chúng tôi chuyển nhiều thông tin kiểu hơn từ phpdoc sang chữ ký hàm, với những lợi thế thông thường mà điều này mang lại

  • Các loại thực sự được thi hành, vì vậy có thể phát hiện sớm các lỗi
  • Bởi vì chúng được thực thi, loại thông tin ít có khả năng trở nên lỗi thời hoặc bỏ lỡ các trường hợp cạnh
  • Các loại được kiểm tra trong quá trình kế thừa, thực thi Nguyên tắc thay thế Liskov
  • Các loại có sẵn thông qua Reflection
  • Cú pháp ít soạn sẵn hơn nhiều so với phpdoc. ”

Các loại liên kết hỗ trợ tất cả các loại có sẵn, với một số hạn chế

  • Loại
    class Test {
        // Error: Callable type not supported for properties.
        public function __construct(public callable $callback) {}
    }
    6 không thể là một phần của liên kết, vì
    class Test {
        // Error: Callable type not supported for properties.
        public function __construct(public callable $callback) {}
    }
    6 có nghĩa là một hàm không trả về bất kỳ giá trị nào
  • Loại
    class Test {
        // Error: Callable type not supported for properties.
        public function __construct(public callable $callback) {}
    }
    8 chỉ được hỗ trợ trong các loại liên kết nhưng không được phép sử dụng loại này như một loại độc lập
  • Ký hiệu loại nullable (
    class Test {
        // Error: Callable type not supported for properties.
        public function __construct(public callable $callback) {}
    }
    9) cũng được cho phép, nghĩa là
    class Test {
        // Error: "var" keyword is not supported.
        public function __construct(var $prop) {}
    }
    0, nhưng chúng tôi không được phép đưa ký hiệu
    class Test {
        // Error: Callable type not supported for properties.
        public function __construct(public callable $callback) {}
    }
    9 vào các loại kết hợp (
    class Test {
        // Error: "var" keyword is not supported.
        public function __construct(var $prop) {}
    }
    2 không được phép và thay vào đó chúng tôi nên sử dụng
    class Test {
        // Error: "var" keyword is not supported.
        public function __construct(var $prop) {}
    }
    3)
  • Nhiều chức năng (tôi. e.
    class Test {
        // Error: "var" keyword is not supported.
        public function __construct(var $prop) {}
    }
    4,
    class Test {
        // Error: "var" keyword is not supported.
        public function __construct(var $prop) {}
    }
    5,
    class Test {
        // Error: "var" keyword is not supported.
        public function __construct(var $prop) {}
    }
    6, v.v. ) bao gồm
    class Test {
        // Error: "var" keyword is not supported.
        public function __construct(var $prop) {}
    }
    7 trong số các loại trả về có thể, loại giả
    class Test {
        // Error: "var" keyword is not supported.
        public function __construct(var $prop) {}
    }
    7 cũng được hỗ trợ

Bạn có thể đọc thêm về Union Type V2 trong RFC

Lỗi loại nhất quán cho các chức năng nội bộ

Khi truyền một tham số thuộc loại không hợp lệ, các hàm bên trong và do người dùng định nghĩa sẽ hoạt động khác đi

Các hàm do người dùng định nghĩa tạo ra một

class Test {
    // Error: "var" keyword is not supported.
    public function __construct(var $prop) {}
}
9, nhưng các hàm bên trong hoạt động theo nhiều cách khác nhau, tùy thuộc vào một số điều kiện. Dù sao đi nữa, hành vi điển hình là đưa ra cảnh báo và trả lại
class Test {
    // Error: Callable type not supported for properties.
    public function __construct(public callable $callback) {}
}
8. Xem ví dụ sau trong PHP 7. 4

// before desugaring
class Point {
    public function __construct(public int $x = 0) {}
}

// after desugaring
class Point {
    public int $x;

    public function __construct(int $x = 0) {
        $this->x = $x;
    }
}
2

Điều này sẽ dẫn đến cảnh báo sau

// before desugaring
class Point {
    public function __construct(public int $x = 0) {}
}

// after desugaring
class Point {
    public int $x;

    public function __construct(int $x = 0) {
        $this->x = $x;
    }
}
3

Nếu

class Test {
    public string $prop;
    public int $explicitProp;

    // Correct
    public function __construct(public int $promotedProp, int $arg) {
        $this->explicitProp = $arg;
    }

    // Error: Redeclaration of property.
    public function __construct(public string $prop) {}
}
1 được bật hoặc thông tin đối số chỉ định loại, hành vi sẽ khác. Trong các trường hợp như vậy, lỗi loại được phát hiện và dẫn đến một
class Test {
    // Error: "var" keyword is not supported.
    public function __construct(var $prop) {}
}
9

Tình huống này sẽ dẫn đến một số vấn đề được giải thích rõ ràng trong

Để loại bỏ những điểm không nhất quán này, RFC này đề xuất tạo các API phân tích tham số nội bộ để luôn tạo ra một

class Test {
    public string $prop;
    public int $explicitProp;

    // Correct
    public function __construct(public int $promotedProp, int $arg) {
        $this->explicitProp = $arg;
    }

    // Error: Redeclaration of property.
    public function __construct(public string $prop) {}
}
3 trong trường hợp loại tham số không khớp

Trong PHP 8, đoạn mã trên đưa ra lỗi sau

// before desugaring
class Point {
    public function __construct(public int $x = 0) {}
}

// after desugaring
class Point {
    public int $x;

    public function __construct(int $x = 0) {
        $this->x = $x;
    }
}
4

ném biểu thức

Trong PHP,

class Test {
    public string $prop;
    public int $explicitProp;

    // Correct
    public function __construct(public int $promotedProp, int $arg) {
        $this->explicitProp = $arg;
    }

    // Error: Redeclaration of property.
    public function __construct(public string $prop) {}
}
4 là một câu lệnh, vì vậy không thể sử dụng nó ở những nơi chỉ cho phép một biểu thức

Triển khai ứng dụng của bạn lên Kinsta - Bắt đầu với Khoản tín dụng $20 ngay bây giờ

Chạy nút của bạn. js, Python, Go, PHP, Ruby, Java và Scala, (hoặc hầu hết mọi ứng dụng khác nếu bạn sử dụng Dockerfiles tùy chỉnh của riêng mình), trong ba bước đơn giản

Triển khai ngay bây giờ và nhận $20 giảm giá

RFC này đề xuất chuyển đổi câu lệnh

class Test {
    public string $prop;
    public int $explicitProp;

    // Correct
    public function __construct(public int $promotedProp, int $arg) {
        $this->explicitProp = $arg;
    }

    // Error: Redeclaration of property.
    public function __construct(public string $prop) {}
}
4 thành một biểu thức để nó có thể được sử dụng trong bất kỳ ngữ cảnh nào cho phép biểu thức. Ví dụ: , toán tử hợp nhất null, v.v.

Xem các ví dụ sau từ RFC

// before desugaring
class Point {
    public function __construct(public int $x = 0) {}
}

// after desugaring
class Point {
    public int $x;

    public function __construct(int $x = 0) {
        $this->x = $x;
    }
}
5

Bản đồ yếu

Bản đồ yếu là một tập hợp dữ liệu (đối tượng) trong đó các khóa được tham chiếu yếu, nghĩa là chúng không bị ngăn thu gom rác

PHP7. 4 đã thêm hỗ trợ như một cách để giữ lại tham chiếu đến một đối tượng mà không ngăn chính đối tượng đó bị hủy. Như Nikita Popov đã chỉ ra,

“Bản thân các tham chiếu yếu thô chỉ có tính hữu ích hạn chế và các bản đồ yếu được sử dụng phổ biến hơn nhiều trong thực tế. Không thể triển khai một bản đồ yếu hiệu quả trên các tham chiếu yếu PHP vì khả năng đăng ký gọi lại hủy không được cung cấp. ”

Đó là lý do tại sao RFC này giới thiệu một lớp

class Test {
    public string $prop;
    public int $explicitProp;

    // Correct
    public function __construct(public int $promotedProp, int $arg) {
        $this->explicitProp = $arg;
    }

    // Error: Redeclaration of property.
    public function __construct(public string $prop) {}
}
6 để tạo các đối tượng được sử dụng làm khóa bản đồ yếu có thể bị hủy và xóa khỏi bản đồ yếu nếu không có bất kỳ tham chiếu nào khác đến đối tượng chính

Trong các quy trình chạy dài, điều này sẽ ngăn rò rỉ bộ nhớ và cải thiện hiệu suất. Xem ví dụ sau từ RFC

// before desugaring
class Point {
    public function __construct(public int $x = 0) {}
}

// after desugaring
class Point {
    public int $x;

    public function __construct(int $x = 0) {
        $this->x = $x;
    }
}
6

Với PHP 8, đoạn mã trên sẽ cho kết quả như sau (xem phần )

// before desugaring
class Point {
    public function __construct(public int $x = 0) {}
}

// after desugaring
class Point {
    public int $x;

    public function __construct(int $x = 0) {
        $this->x = $x;
    }
}
7

Nếu bạn bỏ đặt đối tượng, khóa sẽ tự động bị xóa khỏi bản đồ yếu

// before desugaring
class Point {
    public function __construct(public int $x = 0) {}
}

// after desugaring
class Point {
    public int $x;

    public function __construct(int $x = 0) {
        $this->x = $x;
    }
}
8

Bây giờ kết quả sẽ như sau

// before desugaring
class Point {
    public function __construct(public int $x = 0) {}
}

// after desugaring
class Point {
    public int $x;

    public function __construct(int $x = 0) {
        $this->x = $x;
    }
}
9

Để xem kỹ hơn về Bản đồ yếu, hãy xem RFC. Đề xuất đã được nhất trí thông qua

Dấu phẩy trong danh sách tham số

Dấu phẩy ở cuối là dấu phẩy được thêm vào danh sách các mục trong các ngữ cảnh khác nhau. PHP7. 2 giới thiệu, PHP 7. 3 giới thiệu

PHP 8 hiện giới thiệu dấu phẩy ở cuối danh sách tham số với các hàm, phương thức và bao đóng, như trong ví dụ sau

class Test {
    public function __construct(
        public int $x = 0
    ) {}
}

class Child extends Test {
    public function __construct(
        $x, 
        public int $y = 0,
        public int $z = 0,
    ) {
        parent::__construct($x);
    }
}
0

Đề xuất này được thông qua với số phiếu 58 ăn 1

Cho phép. cú pháp lớp trên các đối tượng

Để lấy tên của một lớp, chúng ta có thể sử dụng cú pháp

class Test {
    public string $prop;
    public int $explicitProp;

    // Correct
    public function __construct(public int $promotedProp, int $arg) {
        $this->explicitProp = $arg;
    }

    // Error: Redeclaration of property.
    public function __construct(public string $prop) {}
}
7. RFC này đề xuất mở rộng cú pháp tương tự cho các đối tượng để giờ đây có thể tìm nạp tên của lớp của một đối tượng nhất định, như trong ví dụ bên dưới

class Test {
    public function __construct(
        public int $x = 0
    ) {}
}

class Child extends Test {
    public function __construct(
        $x, 
        public int $y = 0,
        public int $z = 0,
    ) {
        parent::__construct($x);
    }
}
1

Với PHP 8,

class Test {
    public string $prop;
    public int $explicitProp;

    // Correct
    public function __construct(public int $promotedProp, int $arg) {
        $this->explicitProp = $arg;
    }

    // Error: Redeclaration of property.
    public function __construct(public string $prop) {}
}
8 cung cấp kết quả tương tự như
class Test {
    public string $prop;
    public int $explicitProp;

    // Correct
    public function __construct(public int $promotedProp, int $arg) {
        $this->explicitProp = $arg;
    }

    // Error: Redeclaration of property.
    public function __construct(public string $prop) {}
}
9. Nếu
class Test {
    // Error: Variadic parameter.
    public function __construct(public string ...$strings) {}
}
0 không phải là một đối tượng, nó sẽ đưa ra một ngoại lệ
class Test {
    // Error: "var" keyword is not supported.
    public function __construct(var $prop) {}
}
9

Đề xuất này đã được nhất trí thông qua

Thuộc tính v2

Thuộc tính, còn được gọi là chú thích, là siêu dữ liệu có cấu trúc có thể được sử dụng để chỉ định thuộc tính cho đối tượng, thành phần hoặc tệp

Cho đến PHP 7. 4, doc-comment là cách duy nhất để thêm siêu dữ liệu vào phần khai báo của các lớp, hàm, v.v. Các thuộc tính v2 RFC giới thiệu các thuộc tính PHP, định nghĩa chúng như một dạng siêu dữ liệu có cấu trúc, cú pháp có thể được thêm vào các khai báo của các lớp, thuộc tính, hàm, phương thức, tham số và hằng số

Các thuộc tính được thêm vào trước các khai báo mà chúng đề cập đến. Xem các ví dụ sau từ RFC

class Test {
    public function __construct(
        public int $x = 0
    ) {}
}

class Child extends Test {
    public function __construct(
        $x, 
        public int $y = 0,
        public int $z = 0,
    ) {
        parent::__construct($x);
    }
}
2

Các thuộc tính có thể được thêm vào trước hoặc sau nhận xét khối tài liệu

class Test {
    public function __construct(
        public int $x = 0
    ) {}
}

class Child extends Test {
    public function __construct(
        $x, 
        public int $y = 0,
        public int $z = 0,
    ) {
        parent::__construct($x);
    }
}
3

Mỗi khai báo có thể có một hoặc nhiều thuộc tính và mỗi thuộc tính có thể có một hoặc nhiều giá trị liên quan

class Test {
    public function __construct(
        public int $x = 0
    ) {}
}

class Child extends Test {
    public function __construct(
        $x, 
        public int $y = 0,
        public int $z = 0,
    ) {
        parent::__construct($x);
    }
}
4

Xem RFC để biết tổng quan sâu hơn về các thuộc tính PHP, trường hợp sử dụng và cú pháp thay thế

Đối số được đặt tên

Các đối số được đặt tên cung cấp một cách mới để truyền đối số cho một hàm trong PHP

Đối số được đặt tên cho phép truyền đối số cho hàm dựa trên tên tham số, thay vì vị trí tham số

Chúng ta có thể truyền các đối số được đặt tên cho một hàm bằng cách thêm tên tham số trước giá trị của nó

class Test {
    public function __construct(
        public int $x = 0
    ) {}
}

class Child extends Test {
    public function __construct(
        $x, 
        public int $y = 0,
        public int $z = 0,
    ) {
        parent::__construct($x);
    }
}
5

Chúng tôi cũng được phép sử dụng các từ khóa dành riêng, như trong ví dụ bên dưới

class Test {
    public function __construct(
        public int $x = 0
    ) {}
}

class Child extends Test {
    public function __construct(
        $x, 
        public int $y = 0,
        public int $z = 0,
    ) {
        parent::__construct($x);
    }
}
6

Nhưng chúng tôi không được phép chuyển tên tham số động. Tham số phải là một mã định danh và cú pháp sau không được phép

class Test {
    public function __construct(
        public int $x = 0
    ) {}
}

class Child extends Test {
    public function __construct(
        $x, 
        public int $y = 0,
        public int $z = 0,
    ) {
        parent::__construct($x);
    }
}
7

Theo Nikita Popov, tác giả của RFC này, các đối số được đặt tên mang lại một số lợi thế

Trước hết, các đối số được đặt tên sẽ giúp chúng ta viết mã dễ hiểu hơn vì ý nghĩa của chúng là tự ghi lại. Ví dụ dưới đây từ RFC là tự giải thích

class Test {
    public function __construct(
        public int $x = 0
    ) {}
}

class Child extends Test {
    public function __construct(
        $x, 
        public int $y = 0,
        public int $z = 0,
    ) {
        parent::__construct($x);
    }
}
8

Các đối số được đặt tên không phụ thuộc vào thứ tự. Điều này có nghĩa là chúng ta không buộc phải truyền đối số cho hàm theo thứ tự như chữ ký hàm

Cần một dịch vụ lưu trữ cực nhanh, an toàn và thân thiện với nhà phát triển cho trang web của bạn? . Kiểm tra kế hoạch của chúng tôi

class Test {
    public function __construct(
        public int $x = 0
    ) {}
}

class Child extends Test {
    public function __construct(
        $x, 
        public int $y = 0,
        public int $z = 0,
    ) {
        parent::__construct($x);
    }
}
9

Cũng có thể kết hợp các đối số được đặt tên với các đối số vị trí

abstract class Test {
    // Error: Abstract constructor.
    abstract public function __construct(private $x);
}
 
interface Test {
    // Error: Abstract constructor.
    public function __construct(private $x);
}
0

Một ưu điểm lớn khác của các đối số được đặt tên là chúng chỉ cho phép chỉ định những đối số mà chúng ta muốn thay đổi. Chúng tôi không phải chỉ định các đối số mặc định nếu chúng tôi không muốn ghi đè lên các giá trị mặc định. Ví dụ sau từ RFC làm rõ

abstract class Test {
    // Error: Abstract constructor.
    abstract public function __construct(private $x);
}
 
interface Test {
    // Error: Abstract constructor.
    public function __construct(private $x);
}
1

Quan trọng

Nếu bạn là nhà phát triển WordPress, xin lưu ý rằng tại thời điểm viết bài này, các đối số được đặt tên có thể dẫn đến. Không sử dụng chúng trong sản xuất mà không kiểm tra chu đáo

Các đối số được đặt tên có thể được sử dụng với , như được hiển thị trong ví dụ sau từ RFC

abstract class Test {
    // Error: Abstract constructor.
    abstract public function __construct(private $x);
}
 
interface Test {
    // Error: Abstract constructor.
    public function __construct(private $x);
}
2

Tuy nhiên, việc chuyển các đối số vị trí sau các đối số được đặt tên là không được phép và sẽ dẫn đến lỗi thời gian biên dịch. Điều tương tự cũng xảy ra khi bạn chuyển cùng một tên tham số hai lần

Các đối số được đặt tên rất tiện lợi với các khai báo lớp vì các hàm tạo thường có nhiều tham số và các đối số được đặt tên cung cấp một cách “công thái học” hơn để khai báo một lớp

Để xem kỹ hơn về Đối số được đặt tên, với các ràng buộc, tính không tương thích ngược và một số ví dụ, hãy xem Đối số được đặt tên RFC

Toán tử Nullsafe

RFC này giới thiệu toán tử nullsafe

class Test {
    // Error: Variadic parameter.
    public function __construct(public string ...$strings) {}
}
2 với đánh giá ngắn mạch đầy đủ

Trong đánh giá ngắn mạch, toán tử thứ hai chỉ được đánh giá nếu toán tử thứ nhất không đánh giá thành

class Test {
    // Error: Callable type not supported for properties.
    public function __construct(public callable $callback) {}
}
8. Nếu một người vận hành trong chuỗi đánh giá là
class Test {
    // Error: Callable type not supported for properties.
    public function __construct(public callable $callback) {}
}
8, thì việc thực hiện toàn bộ chuỗi sẽ dừng lại và đánh giá là
class Test {
    // Error: Callable type not supported for properties.
    public function __construct(public callable $callback) {}
}
8

Xem xét các ví dụ sau từ RFC

abstract class Test {
    // Error: Abstract constructor.
    abstract public function __construct(private $x);
}
 
interface Test {
    // Error: Abstract constructor.
    public function __construct(private $x);
}
3

Nếu

class Test {
    // Error: Variadic parameter.
    public function __construct(public string ...$strings) {}
}
6 là null, phương thức
class Test {
    // Error: Variadic parameter.
    public function __construct(public string ...$strings) {}
}
7 không được gọi và
class Test {
    // Error: Variadic parameter.
    public function __construct(public string ...$strings) {}
}
8 được đặt thành
class Test {
    // Error: Callable type not supported for properties.
    public function __construct(public callable $callback) {}
}
8

Xem RFC toán tử nullsafe để biết thêm các ví dụ, ngoại lệ và phạm vi trong tương lai

So sánh chuỗi Saner với số

Trong các phiên bản PHP trước, khi thực hiện so sánh không nghiêm ngặt giữa các chuỗi và số, trước tiên, PHP sẽ chuyển chuỗi thành một số, sau đó thực hiện so sánh giữa các số nguyên hoặc số float. Ngay cả khi hành vi này khá hữu ích trong một số trường hợp, nó có thể tạo ra kết quả sai và cũng có thể dẫn đến lỗi và/hoặc sự cố bảo mật

Xem xét ví dụ sau từ RFC

abstract class Test {
    // Error: Abstract constructor.
    abstract public function __construct(private $x);
}
 
interface Test {
    // Error: Abstract constructor.
    public function __construct(private $x);
}
4

PHP 8 giới thiệu chuỗi Saner để so sánh số, nhằm mục đích làm cho chuỗi so sánh với số hợp lý hơn. Theo lời của Nikita Popov,

RFC này dự định cung cấp cho chuỗi để so sánh số một hành vi hợp lý hơn. Khi so sánh với một chuỗi số, hãy sử dụng phép so sánh số (giống như bây giờ). Nếu không, hãy chuyển đổi số thành chuỗi và sử dụng phép so sánh chuỗi

Bảng sau đây so sánh hành vi của so sánh chuỗi với số trong các phiên bản PHP trước đó và trong PHP 8

abstract class Test {
    // Error: Abstract constructor.
    abstract public function __construct(private $x);
}
 
interface Test {
    // Error: Abstract constructor.
    public function __construct(private $x);
}
5

Đọc thêm về nhiều ý nghĩa của thay đổi này và cách so sánh chuỗi với số thay đổi trong PHP 8 trong RFC chính thức từ Nikita Popov

Chuỗi số Saner

Trong PHP, các chuỗi chứa số rơi vào

  • chuỗi số. các chuỗi chứa một số tùy ý đứng trước khoảng trắng
  • Chuỗi số hàng đầu. chuỗi có ký tự đầu là chuỗi số và ký tự cuối không phải là số
  • chuỗi không phải số. chuỗi không thuộc cả hai loại trước đó

Chuỗi số và chuỗi số đầu được xử lý khác nhau tùy thuộc vào thao tác được thực hiện. Ví dụ

  • Chuyển đổi chuỗi thành số rõ ràng (i. e. kiểu phôi
    class Point {
        public function __construct(
            public int $x = 0,
            public int $y = 0,
            public int $z = 0,
        ) {}
    }
    00 và
    class Point {
        public function __construct(
            public int $x = 0,
            public int $y = 0,
            public int $z = 0,
        ) {}
    }
    01) chuyển đổi số và chuỗi số ở đầu số. Chuyển đổi rõ ràng một chuỗi không phải số thành một số tạo ra 0
  • Chuyển đổi chuỗi ẩn thành số (i. e. không khai báo
    class Point {
        public function __construct(
            public int $x = 0,
            public int $y = 0,
            public int $z = 0,
        ) {}
    }
    02) dẫn đến các kết quả khác nhau đối với chuỗi số và chuỗi không phải số. Chuyển đổi chuỗi không phải số thành số ném một
    class Test {
        // Error: "var" keyword is not supported.
        public function __construct(var $prop) {}
    }
    9
  • class Point {
        public function __construct(
            public int $x = 0,
            public int $y = 0,
            public int $z = 0,
        ) {}
    }
    04 chỉ trả về true cho các chuỗi số

Độ lệch chuỗi, phép toán số học, phép toán tăng và giảm, so sánh chuỗi với chuỗi và phép toán bitwise cũng dẫn đến các kết quả khác nhau

RFC này đề xuất

Hợp nhất các chế độ chuỗi số khác nhau thành một khái niệm duy nhất. Các ký tự số chỉ được phép có cả khoảng trắng ở đầu và cuối. Bất kỳ loại chuỗi nào khác không phải là số và sẽ ném TypeErrors khi được sử dụng trong ngữ cảnh số

Điều này có nghĩa là, tất cả các chuỗi hiện đang phát ra E_NOTICE “Đã gặp phải giá trị số không được định dạng tốt” sẽ được phân loại lại thành E_WARNING “Đã gặp phải giá trị không phải là số” trừ khi chuỗi có số ở đầu chỉ chứa khoảng trắng ở cuối. Và các trường hợp khác nhau hiện đang phát ra E_WARNING sẽ được thăng cấp lên

class Test {
    // Error: "var" keyword is not supported.
    public function __construct(var $prop) {}
}
9s

Để biết tổng quan sâu hơn về các chuỗi số trong PHP 8, với các ví dụ mã, ngoại lệ và các vấn đề tương thích ngược, hãy xem RFC

Biểu thức đối sánh v2

Biểu thức

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
06 mới khá giống với biểu thức
class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
07 nhưng có ngữ nghĩa an toàn hơn và cho phép trả về các giá trị

Để hiểu sự khác biệt giữa hai cấu trúc điều khiển, hãy xem xét ví dụ

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
07 sau đây từ RFC

abstract class Test {
    // Error: Abstract constructor.
    abstract public function __construct(private $x);
}
 
interface Test {
    // Error: Abstract constructor.
    public function __construct(private $x);
}
6

Bây giờ chúng ta có thể nhận được kết quả tương tự như đoạn mã trên với biểu thức

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
06 sau đây

abstract class Test {
    // Error: Abstract constructor.
    abstract public function __construct(private $x);
}
 
interface Test {
    // Error: Abstract constructor.
    public function __construct(private $x);
}
7

Một lợi thế đáng kể của việc sử dụng biểu thức

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
06 mới là trong khi
class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
07 so sánh các giá trị một cách lỏng lẻo (_______2_______12) có khả năng dẫn đến kết quả không mong muốn, thì với
class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
06, so sánh là kiểm tra danh tính (
class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
14)

Biểu thức

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
06 cũng có thể chứa nhiều biểu thức được phân tách bằng dấu phẩy cho phép cú pháp ngắn gọn hơn (nguồn)

abstract class Test {
    // Error: Abstract constructor.
    abstract public function __construct(private $x);
}
 
interface Test {
    // Error: Abstract constructor.
    public function __construct(private $x);
}
8

Để biết thêm các ví dụ và trường hợp sử dụng, hãy xem biểu thức Khớp v2 RFC và tài liệu PHP

Kiểm tra loại nghiêm ngặt hơn cho toán tử số học/bitwise

Trong các phiên bản PHP trước, cho phép áp dụng các toán tử số học và bitwise cho một mảng, tài nguyên hoặc đối tượng không quá tải. Dù sao, hành vi đôi khi không nhất quán

Trong RFC này, Nikita Popov cho thấy hành vi đó có thể phi lý như thế nào bằng một ví dụ đơn giản

abstract class Test {
    // Error: Abstract constructor.
    abstract public function __construct(private $x);
}
 
interface Test {
    // Error: Abstract constructor.
    public function __construct(private $x);
}
9

Nikita giải thích cách áp dụng toán tử số học hoặc bitwise cho mảng, tài nguyên hoặc đối tượng không bị quá tải

Toán tử +, -, *, /, **

  • Ném ngoại lệ Lỗi trên toán hạng mảng. (Không bao gồm + nếu cả hai toán hạng là mảng. )
  • Âm thầm chuyển đổi toán hạng tài nguyên thành ID tài nguyên dưới dạng số nguyên
  • Chuyển đổi một toán hạng đối tượng thành một số nguyên, trong khi ném một thông báo

Operators %, <<, >>, &, |, ^:

  • Âm thầm chuyển đổi một toán hạng mảng thành số nguyên 0 nếu trống hoặc số nguyên 1 nếu không trống
  • Âm thầm chuyển đổi toán hạng tài nguyên thành ID tài nguyên dưới dạng số nguyên
  • Chuyển đổi một toán hạng đối tượng thành một số nguyên, trong khi ném một thông báo

Người điều hành ~

  • Ném một ngoại lệ Lỗi cho toán hạng mảng, tài nguyên và đối tượng

Toán tử ++ và –

  • Im lặng không làm gì nếu toán hạng là một mảng, tài nguyên hoặc đối tượng

Với PHP 8, mọi thứ thay đổi và hành vi giống nhau đối với tất cả các toán tử số học và bitwise

Ném một ngoại lệ

class Test {
    // Error: "var" keyword is not supported.
    public function __construct(var $prop) {}
}
9 cho toán hạng mảng, tài nguyên và đối tượng

Các hàm PHP mới

PHP 8 mang đến một số chức năng mới cho ngôn ngữ

str_contains

Trước PHP 8, strstr và strpos là các tùy chọn điển hình để các nhà phát triển tìm kiếm một cây kim bên trong một chuỗi nhất định. Vấn đề là cả hai chức năng không được coi là rất trực quan và việc sử dụng chúng có thể gây nhầm lẫn cho các nhà phát triển PHP mới. Xem ví dụ sau

class Test {
    // Error: Using null default on non-nullable property
    public function __construct(public Type $prop = null) {}

    // Correct: Make the type explicitly nullable instead
    public function __construct(public ?Type $prop = null) {}
}
0

Trong ví dụ trên, chúng tôi đã sử dụng toán tử so sánh

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
17 để kiểm tra xem hai giá trị có cùng loại không. Điều này ngăn chúng tôi gặp lỗi

“Hàm này có thể trả về giá trị Boolean FALSE, nhưng cũng có thể trả về giá trị không phải Boolean đánh giá là FALSE. […] Sử dụng toán tử === để kiểm tra giá trị trả về của hàm này. ”

Hơn nữa, một số khung cung cấp các hàm trợ giúp để tìm kiếm một giá trị bên trong một chuỗi nhất định (xem ví dụ)

Bây giờ, RFC này đề xuất giới thiệu một chức năng mới cho phép tìm kiếm bên trong một chuỗi.

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
18

class Test {
    // Error: Using null default on non-nullable property
    public function __construct(public Type $prop = null) {}

    // Correct: Make the type explicitly nullable instead
    public function __construct(public ?Type $prop = null) {}
}
1

Cách sử dụng của nó khá đơn giản.

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
18 kiểm tra nếu tìm thấy
class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
20 trong
class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
21 và trả về
class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
22 hoặc
class Test {
    // Error: "var" keyword is not supported.
    public function __construct(var $prop) {}
}
7 tương ứng

Vì vậy, nhờ có

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
18, chúng ta có thể viết đoạn mã sau

class Test {
    // Error: Using null default on non-nullable property
    public function __construct(public Type $prop = null) {}

    // Correct: Make the type explicitly nullable instead
    public function __construct(public ?Type $prop = null) {}
}
2

Cái nào dễ đọc hơn và ít bị lỗi hơn (xem mã này đang hoạt động)
Tại thời điểm viết bài này,

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
18 phân biệt chữ hoa chữ thường, nhưng điều này có thể thay đổi trong tương lai

Đề xuất

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
18 được thông qua với 43 đến 9 phiếu bầu

str_starts_with() và str_ends_with()

Ngoài chức năng

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
18, hai chức năng mới cho phép tìm kiếm một cây kim bên trong một chuỗi nhất định.
class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
28 và
class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
29

Các hàm mới này kiểm tra xem một chuỗi đã cho bắt đầu hay kết thúc bằng một chuỗi khác

class Test {
    // Error: Using null default on non-nullable property
    public function __construct(public Type $prop = null) {}

    // Correct: Make the type explicitly nullable instead
    public function __construct(public ?Type $prop = null) {}
}
3

Cả hai hàm đều trả về

class Test {
    // Error: "var" keyword is not supported.
    public function __construct(var $prop) {}
}
7 nếu
class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
20 dài hơn
class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
21

Theo Will Hudgins, tác giả của RFC này,

“Chức năng

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
28 và
class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
29 thường cần thiết đến mức nhiều khung công tác PHP chính hỗ trợ nó, bao gồm , , , và Phalcon. ”

Nhờ có chúng, giờ đây chúng tôi có thể tránh sử dụng các hàm dưới mức tối ưu và ít trực quan hơn như

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
35,
class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
36. Cả hai hàm đều phân biệt chữ hoa chữ thường

class Test {
    // Error: Using null default on non-nullable property
    public function __construct(public Type $prop = null) {}

    // Correct: Make the type explicitly nullable instead
    public function __construct(public ?Type $prop = null) {}
}
4

Bạn có thể thấy mã này đang hoạt động

RFC này đã được phê duyệt với 51 đến 4 phiếu bầu

get_debug_type

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
37 là một hàm PHP mới trả về kiểu của một biến. Hàm mới hoạt động theo cách tương tự như hàm
class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
38, nhưng
class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
37 trả về tên kiểu gốc và giải quyết tên lớp

Đó là một cải tiến tốt cho ngôn ngữ, vì

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
40 không hữu ích cho việc kiểm tra loại

RFC cung cấp hai ví dụ hữu ích để hiểu sự khác biệt giữa hàm

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
41 mới và hàm
class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
40. Ví dụ đầu tiên cho thấy
class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
38 tại nơi làm việc

class Test {
    // Error: Using null default on non-nullable property
    public function __construct(public Type $prop = null) {}

    // Correct: Make the type explicitly nullable instead
    public function __construct(public ?Type $prop = null) {}
}
5

Với PHP 8, chúng ta có thể sử dụng

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
37, thay vào đó

class Test {
    // Error: Using null default on non-nullable property
    public function __construct(public Type $prop = null) {}

    // Correct: Make the type explicitly nullable instead
    public function __construct(public ?Type $prop = null) {}
}
6

Bảng sau đây hiển thị các giá trị trả về của

class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
37 và
class Point {
    public function __construct(
        public int $x = 0,
        public int $y = 0,
        public int $z = 0,
    ) {}
}
38

Valuegettype()get_debug_type()1integerint0. 1doublefloattruebooleanboolfalsebooleanboolnullNULLnull“WordPress”stringstring[1,2,3]arrayarrayMột lớp có tên “Foo\Bar”đối tượngFoo\BarMột đối tượng lớp ẩn danh[email được bảo vệ]

RFC bổ sung

Dưới đây là danh sách nhanh các cải tiến bổ sung đã được phê duyệt đi kèm với PHP 8

  1. Giao diện có thể xâu chuỗi. RFC này giới thiệu giao diện Stringable được tự động thêm vào các lớp triển khai. Mục tiêu chính ở đây là sử dụng loại công đoàn
    class Point {
        public function __construct(
            public int $x = 0,
            public int $y = 0,
            public int $z = 0,
        ) {}
    }
    48
  2. DOM Living Standard API mới trong ext/dom. RFC này đề xuất triển khai DOM Living Standard hiện tại cho phần mở rộng PHP DOM bằng cách giới thiệu các giao diện và thuộc tính công khai mới
  3. Kiểu trả về tĩnh. PHP 8 giới thiệu việc sử dụng
    class Point {
        public function __construct(
            public int $x = 0,
            public int $y = 0,
            public int $z = 0,
        ) {}
    }
    49 làm kiểu trả về bên cạnh các kiểu
    class Point {
        public function __construct(
            public int $x = 0,
            public int $y = 0,
            public int $z = 0,
        ) {}
    }
    50 và
    class Point {
        public function __construct(
            public int $x = 0,
            public int $y = 0,
            public int $z = 0,
        ) {}
    }
    51
  4. Chỉnh sửa cú pháp biến. RFC này giải quyết một số mâu thuẫn còn lại trong cú pháp biến của PHP

Điểm chuẩn hiệu suất PHP 8

Nếu bạn đang thắc mắc PHP 8 nhanh như thế nào, chúng tôi có câu trả lời. Chúng tôi đã đo điểm chuẩn cho 20 nền tảng/cấu hình PHP trên 7 phiên bản PHP khác nhau (5. 6, 7. 0, 7. 1, 7. 2, 7. 3 và 8. 0)

PHP8. 0 nổi lên như người chiến thắng trong hầu hết các nền tảng hỗ trợ nó, bao gồm cả WordPress và Laravel

Sự khác biệt giữa PHP 7 và 8
Tổng hợp điểm chuẩn PHP của các nền tảng hàng đầu

Chẳng hạn, WordPress trên PHP 8. 0 có thể xử lý 18. Nhiều hơn 4% yêu cầu mỗi giây so với PHP 7. 4. Tương tự như vậy, Laravel trên PHP 8. 0 có thể chạy 8. Nhiều hơn 5% yêu cầu mỗi giây so với PHP 7. 3

Nếu trang web hoặc ứng dụng của bạn hoàn toàn tương thích với PHP 8. 0, bạn nên lập kế hoạch cập nhật môi trường máy chủ của mình lên PHP 8. 0 càng sớm càng tốt. Bạn (và người dùng của bạn) chắc chắn sẽ đánh giá cao những lợi ích về hiệu suất của nó. Tuy nhiên, vui lòng kiểm tra trang web của bạn kỹ lưỡng trước khi cập nhật

Bạn có thể đọc bài viết điểm chuẩn PHP của chúng tôi để biết thêm thông tin, chẳng hạn như dữ liệu hiệu suất chi tiết, thông tin chi tiết và biểu đồ đẹp

PHP 8 đã được phát hành cho GA và mang lại nhiều tính năng và tối ưu hóa cho ngôn ngữ này. 🚀 Hãy xem phần đi sâu của chúng tôi vào PHP 8. Nhấp để Tweet

Bản tóm tắt

Thật là một chuyến đi. Trong bài đăng này, chúng tôi đã đề cập đến các tính năng và tối ưu hóa thú vị nhất đi kèm với PHP 8. Điều được chờ đợi nhất chắc chắn là trình biên dịch Just in Time, nhưng còn nhiều hơn thế nữa với PHP 8

Đảm bảo đánh dấu bài đăng trên blog này để bạn tham khảo trong tương lai. 🤓

Bây giờ đến lượt bạn. bạn đã sẵn sàng thử nghiệm các tính năng mới của PHP chưa?


Nhận tất cả các ứng dụng, cơ sở dữ liệu và trang web WordPress của bạn trực tuyến và dưới một mái nhà. Nền tảng đám mây hiệu suất cao, đầy đủ tính năng của chúng tôi bao gồm

  • Dễ dàng thiết lập và quản lý trong bảng điều khiển MyKinsta
  • Hỗ trợ chuyên gia 24/7
  • Mạng và phần cứng Google Cloud Platform tốt nhất, được cung cấp bởi Kubernetes để có khả năng mở rộng tối đa
  • Tích hợp Cloudflare cấp doanh nghiệp cho tốc độ và bảo mật
  • Tiếp cận đối tượng toàn cầu với tối đa 35 trung tâm dữ liệu và 275 PoP trên toàn thế giới

Hãy tự kiểm tra với $20 trong tháng đầu tiên của Lưu trữ ứng dụng hoặc Lưu trữ cơ sở dữ liệu. Khám phá kế hoạch của chúng tôi hoặc nói chuyện với bộ phận bán hàng để tìm thấy sự phù hợp nhất của bạn

Tôi nên sử dụng PHP 7 hay 8?

Ngoài ra, phiên bản PHP mới hơn hoạt động tốt hơn các phiên bản cũ. Sự gia tăng đáng kể về hiệu suất và bảo mật có thể là tất cả những gì cần thiết để cải thiện và đảm bảo trải nghiệm người dùng tích cực trên trang web của bạn. PHP 8 nhanh hơn đáng kể so với PHP 7 theo nhiều tiêu chuẩn web khác nhau.

Sự khác biệt giữa PHP 7 là gì. 4 và PHP 8?

Q. Sự khác biệt giữa PHP 7 là gì. 4 và 8? . Một trong nhiều ví dụ là, WordPress trên PHP 8. 0 có thể xử lý 18. Nhiều hơn 4% yêu cầu mỗi giây so với PHP 7. 4 . Hơn nữa, Laravel trên PHP 8. 0 có thể chạy 8. Nhiều hơn 5% yêu cầu mỗi giây so với PHP 7. 3.

Tôi có nên sử dụng phiên bản PHP 8 không?

PHP 8 cho phép bạn viết mã ngắn gọn và xây dựng các ứng dụng mẫu mực hơn với những thay đổi và cải tiến thú vị đối với các RFC trước đó. Xem xét các cải tiến mới, sẽ là một tội ác nếu không nâng cấp phiên bản PHP hiện tại của bạn lên PHP 8. 1 trên trang web WordPress của bạn .

Điều gì đã thay đổi trong PHP 8?

PHP8. 0 là một bản cập nhật lớn của ngôn ngữ PHP. Nó chứa nhiều tính năng và tối ưu hóa mới bao gồm các đối số được đặt tên, các loại liên kết, thuộc tính, quảng cáo thuộc tính hàm tạo, biểu thức khớp, toán tử nullsafe, JIT và các cải tiến trong hệ thống loại, xử lý lỗi và tính nhất quán