Các thuộc tính lớp đã nhập đã được thêm vào trong PHP 7. 4 và cung cấp một cải tiến lớn cho hệ thống kiểu của PHP. Những thay đổi này hoàn toàn được chọn tham gia và không phá vỡ các phiên bản trước
Trong bài đăng này, chúng tôi sẽ xem xét tính năng này một cách chuyên sâu, nhưng trước tiên hãy bắt đầu bằng cách tóm tắt những điểm quan trọng nhất
- Chúng có sẵn kể từ PHP 7. 4 dự kiến ra mắt vào tháng 11/2019
- Chúng chỉ khả dụng trong các lớp và yêu cầu công cụ sửa đổi quyền truy cập.
7,class Foo { public int $bar; } $foo = new Foo;
8 hoặcclass Foo { public int $bar; } $foo = new Foo;
9;class Foo { public int $bar; } $foo = new Foo;
- Tất cả các loại đều được phép, ngoại trừ
1 vàvar_dump[$foo->bar]; Fatal error: Uncaught Error: Typed property Foo::$bar must not be accessed before initialization
2var_dump[$foo->bar]; Fatal error: Uncaught Error: Typed property Foo::$bar must not be accessed before initialization
Đây là những gì họ trông giống như trong hành động
class Foo
{
public int $a;
public ?string $b = 'foo';
private Foo $prop;
protected static string $static = 'default';
}
Nếu bạn không chắc chắn về lợi ích bổ sung của các loại, tôi khuyên bạn nên đọc bài đăng này trước
Chưa khởi tạo
Trước khi xem những nội dung thú vị, có một khía cạnh quan trọng về các thuộc tính đã nhập cần nói đến trước tiên
Bất chấp những gì bạn có thể nghĩ ngay từ cái nhìn đầu tiên, mã sau đây là hợp lệ
class Foo
{
public int $bar;
}
$foo = new Foo;
Mặc dù giá trị của
var_dump[$foo->bar];
Fatal error: Uncaught Error: Typed property Foo::$bar
must not be accessed before initialization
3 không phải là số nguyên sau khi tạo một đối tượng của var_dump[$foo->bar];
Fatal error: Uncaught Error: Typed property Foo::$bar
must not be accessed before initialization
4, PHP sẽ chỉ đưa ra lỗi khi truy cập var_dump[$foo->bar];
Fatal error: Uncaught Error: Typed property Foo::$bar
must not be accessed before initialization
3var_dump[$foo->bar];
Fatal error: Uncaught Error: Typed property Foo::$bar
must not be accessed before initialization
Như bạn có thể đọc từ thông báo lỗi, có một loại "trạng thái biến" mới. chưa khởi tạo
Nếu
var_dump[$foo->bar];
Fatal error: Uncaught Error: Typed property Foo::$bar
must not be accessed before initialization
3 không có loại, giá trị của nó sẽ đơn giản là var_dump[$foo->bar];
Fatal error: Uncaught Error: Typed property Foo::$bar
must not be accessed before initialization
7. Tuy nhiên, các loại có thể là nullable, vì vậy không thể xác định xem một thuộc tính nullable đã nhập đã được đặt hay đơn giản là bị lãng quên. Đó là lý do tại sao "chưa khởi tạo" đã được thêm vàoCó bốn điều quan trọng cần nhớ về uninitialized
- Bạn không thể đọc từ các thuộc tính chưa được khởi tạo, làm như vậy sẽ dẫn đến lỗi nghiêm trọng
- Vì trạng thái chưa được khởi tạo được kiểm tra khi truy cập một thuộc tính, nên bạn có thể tạo một đối tượng có thuộc tính chưa được khởi tạo, mặc dù loại của nó không thể vô hiệu hóa
- Bạn có thể ghi vào một thuộc tính chưa được khởi tạo trước khi đọc từ nó
- Sử dụng
8 trên một thuộc tính đã nhập sẽ làm cho nó không được khởi tạo, trong khi việc hủy đặt một thuộc tính chưa được nhập sẽ khiến nó trở thànhvar_dump[$foo->bar]; Fatal error: Uncaught Error: Typed property Foo::$bar must not be accessed before initialization
7var_dump[$foo->bar]; Fatal error: Uncaught Error: Typed property Foo::$bar must not be accessed before initialization
Đặc biệt lưu ý rằng đoạn mã sau, trong đó một thuộc tính không thể vô hiệu hóa, chưa được khởi tạo được đặt sau khi xây dựng đối tượng, là hợp lệ
class Foo
{
public int $bar;
}
$foo = new Foo;
6Mặc dù trạng thái chưa được khởi tạo chỉ được kiểm tra khi đọc giá trị của một thuộc tính, nhưng việc xác thực kiểu được thực hiện khi ghi vào nó. Điều này có nghĩa là bạn có thể chắc chắn rằng không có loại không hợp lệ nào sẽ kết thúc dưới dạng giá trị của thuộc tính
Xem video mới nhất của tôi
PHP trong 1 phút
Mặc định và hàm tạo
Chúng ta hãy xem xét kỹ hơn cách các giá trị đã nhập có thể được khởi tạo. Trong trường hợp loại vô hướng, có thể cung cấp giá trị mặc định
class Foo
{
public int $bar;
}
$foo = new Foo;
7Lưu ý rằng bạn chỉ có thể sử dụng
var_dump[$foo->bar];
Fatal error: Uncaught Error: Typed property Foo::$bar
must not be accessed before initialization
7 làm mặc định nếu loại thực sự là nullable. Điều này có vẻ hiển nhiên, nhưng có một số hành vi kế thừa với các giá trị mặc định của tham số trong đó những điều sau đây được cho phépclass Foo
{
public int $bar;
}
$foo = new Foo;
9May mắn thay, hành vi khó hiểu này không được phép với các thuộc tính đã nhập
Cũng lưu ý rằng không thể có giá trị mặc định với
class Foo
{
public int $bar;
}
$foo = new Foo;
61 hoặc loại lớp. Bạn nên sử dụng hàm tạo để đặt giá trị mặc định của chúngTất nhiên, vị trí rõ ràng để khởi tạo các giá trị đã nhập sẽ là hàm tạo
class Foo
{
public int $bar;
}
$foo = new Foo;
1Nhưng cũng hãy nhớ những gì tôi đã đề cập trước đây. nó hợp lệ để ghi vào một thuộc tính chưa được khởi tạo, bên ngoài hàm tạo. Miễn là không có gì được đọc từ một thuộc tính, kiểm tra chưa khởi tạo sẽ không được thực hiện
các loại các loại
Vì vậy, chính xác những gì có thể được gõ và làm thế nào?
Về loại có sẵn thì hầu như loại nào cũng dùng được, trừ
var_dump[$foo->bar];
Fatal error: Uncaught Error: Typed property Foo::$bar
must not be accessed before initialization
1 và var_dump[$foo->bar];
Fatal error: Uncaught Error: Typed property Foo::$bar
must not be accessed before initialization
2Vì
var_dump[$foo->bar];
Fatal error: Uncaught Error: Typed property Foo::$bar
must not be accessed before initialization
1 có nghĩa là không có giá trị nên không thể sử dụng nó để nhập giá trị. Tuy nhiên, var_dump[$foo->bar];
Fatal error: Uncaught Error: Typed property Foo::$bar
must not be accessed before initialization
2 có nhiều sắc thái hơn một chútHãy xem, một "có thể gọi được" trong PHP có thể được viết như vậy
class Foo
{
public int $bar;
}
$foo = new Foo;
7Giả sử bạn có mã [bị hỏng] sau
class Foo
{
public int $bar;
}
$foo = new Foo;
8Trong ví dụ này,
class Foo
{
public int $bar;
}
$foo = new Foo;
67 đề cập đến class Foo
{
public int $bar;
}
$foo = new Foo;
68 riêng tư, nhưng được gọi trong ngữ cảnh của var_dump[$foo->bar];
Fatal error: Uncaught Error: Typed property Foo::$bar
must not be accessed before initialization
4. Vì vấn đề này, chúng tôi đã quyết định không thêm hỗ trợ var_dump[$foo->bar];
Fatal error: Uncaught Error: Typed property Foo::$bar
must not be accessed before initialization
2Tuy nhiên, đó không phải là vấn đề lớn, bởi vì
class Foo
{
public int $bar;
}
$foo = new Foo;
71 là một loại hợp lệ, nó sẽ ghi nhớ bối cảnh của class Foo
{
public int $bar;
}
$foo = new Foo;
72 nơi nó được xây dựngNgoài ra, đây là danh sách tất cả các loại có sẵn
- bool
- int
- trôi nổi
- chuỗi
- mảng
- lặp đi lặp lại
- vật
- ?
- bản thân và bố mẹ
- Lớp & giao diện
Ép buộc và các loại nghiêm ngặt
PHP, là ngôn ngữ động mà chúng ta yêu và ghét, sẽ cố gắng ép buộc hoặc chuyển đổi các loại bất cứ khi nào có thể. Giả sử bạn chuyển một chuỗi mà bạn mong đợi một số nguyên, PHP sẽ thử và tự động chuyển đổi chuỗi đó
var_dump[$foo->bar];
Fatal error: Uncaught Error: Typed property Foo::$bar
must not be accessed before initialization
5Các nguyên tắc tương tự áp dụng cho các thuộc tính đã nhập. Đoạn mã sau hợp lệ và sẽ chuyển đổi
class Foo
{
public int $bar;
}
$foo = new Foo;
73 thành class Foo
{
public int $bar;
}
$foo = new Foo;
74class Foo
{
public int $bar;
}
$foo = new Foo;
0Nếu bạn không thích hành vi này, bạn có thể tắt nó bằng cách khai báo các loại nghiêm ngặt
class Foo
{
public int $bar;
}
$foo = new Foo;
1Loại phương sai và kế thừa
Mặc dù PHP 7. 4 giới thiệu, thuộc tính gõ vẫn bất biến. Điều này có nghĩa là những điều sau đây không hợp lệ
class Foo
{
public int $bar;
}
$foo = new Foo;
2Nếu ví dụ trên có vẻ không đáng kể, bạn nên xem qua ví dụ sau
class Foo
{
public int $bar;
}
$foo = new Foo;
3PHP sẽ thay thế
class Foo
{
public int $bar;
}
$foo = new Foo;
75 đằng sau hậu trường bằng lớp cụ thể mà nó đề cập đến, trước khi chạy mã. Điều này có nghĩa là lỗi tương tự sẽ xảy ra trong ví dụ này. Cách duy nhất để xử lý nó, là làm như sauclass Foo
{
public int $bar;
}
$foo = new Foo;
4Nói về tính kế thừa, bạn có thể thấy khó tìm ra bất kỳ trường hợp sử dụng tốt nào để ghi đè lên các loại thuộc tính được kế thừa
Mặc dù tôi đồng ý với quan điểm đó, nhưng cần lưu ý rằng có thể thay đổi loại tài sản thừa kế, nhưng chỉ khi công cụ sửa đổi quyền truy cập cũng thay đổi từ
class Foo
{
public int $bar;
}
$foo = new Foo;
9 thành class Foo
{
public int $bar;
}
$foo = new Foo;
8 hoặc class Foo
{
public int $bar;
}
$foo = new Foo;
7Mã sau đây là hợp lệ
class Foo
{
public int $bar;
}
$foo = new Foo;
5Tuy nhiên, không được phép thay đổi loại từ nullable thành non-nullable hoặc đảo ngược
class Foo
{
public int $bar;
}
$foo = new Foo;
6Nhận thấy một tpyo? . Nếu bạn muốn cập nhật những gì đang diễn ra trên blog này, bạn có thể theo dõi tôi trên Twitter hoặc đăng ký nhận bản tin của tôi. Đăng ký email
Còn nữa
Giống như đã nói ở đầu bài đăng này, các thuộc tính đã nhập là một bổ sung chính cho PHP. Còn rất nhiều điều để nói về họ. Tôi khuyên bạn nên đọc qua RFC để biết tất cả các chi tiết nhỏ gọn
Nếu bạn chưa quen với PHP 7. 4, bạn có thể muốn đọc danh sách đầy đủ các thay đổi đã thực hiện và các tính năng được thêm vào. Thành thật mà nói, đây là một trong những bản phát hành hay nhất trong một thời gian dài và đáng để bạn dành thời gian
Cuối cùng, nếu bạn có bất kỳ suy nghĩ nào muốn chia sẻ về chủ đề này, tôi rất muốn nghe ý kiến từ bạn. Bạn có thể liên hệ với tôi qua Twitter hoặc e-mail