Biến riêng của lớp PHP

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.
    class Foo
    {
        public int $bar;
    }
    
    $foo = new Foo;
    7,
    class Foo
    {
        public int $bar;
    }
    
    $foo = new Foo;
    8 hoặc
    class Foo
    {
        public int $bar;
    }
    
    $foo = new Foo;
    9;
  • Tất cả các loại đều được phép, ngoại 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
    2

Đâ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
3

var_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ào

Có 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
    var_dump($foo->bar);
    
    Fatal error: Uncaught Error: Typed property Foo::$bar 
    must not be accessed before initialization
    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ành
    var_dump($foo->bar);
    
    Fatal error: Uncaught Error: Typed property Foo::$bar 
    must not be accessed before initialization
    7

Đặ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;
6

Mặ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

Biến riêng của lớp PHP

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;
7

Lư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ép

class Foo
{
    public int $bar;
}

$foo = new Foo;
9

May 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úng

Tấ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;
1

Như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
2

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út

Hã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;
7

Giả sử bạn có mã (bị hỏng) sau

class Foo
{
    public int $bar;
}

$foo = new Foo;
8

Trong 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
2

Tuy 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ựng

Ngoà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
5

Cá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;
74

class Foo
{
    public int $bar;
}

$foo = new Foo;
0

Nế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;
1

Loạ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;
2

Nế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;
3

PHP 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ư sau

class Foo
{
    public int $bar;
}

$foo = new Foo;
4

Nó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;
7

Mã sau đây là hợp lệ

class Foo
{
    public int $bar;
}

$foo = new Foo;
5

Tuy 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;
6

Nhậ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

Một lớp có thể ở chế độ riêng tư trong PHP không?

Nó đánh dấu một thuộc tính hoặc phương thức là riêng tư. Các thuộc tính và phương thức riêng chỉ có thể được sử dụng bởi lớp mà thuộc tính hoặc phương thức đó được định nghĩa . Các lớp dẫn xuất và mã bên ngoài không thể sử dụng chúng.

Các biến lớp có thể là riêng tư không?

Các biến lớp được khai báo là riêng tư không thể được tham chiếu từ các lớp khác, chúng chỉ hiển thị trong lớp của chính chúng . Việc sử dụng các biến lớp riêng tư thay vì công khai được coi là phương pháp lập trình tốt hơn và bạn nên đặt mục tiêu làm điều này trong phần còn lại của khóa học.

Làm cách nào tôi có thể truy cập biến riêng tư từ một lớp khác trong PHP?

Bạn cần đặt quyền truy cập thành được bảo vệ. Riêng tư có nghĩa là nó chỉ có thể được truy cập từ bên trong lớp của chính nó và không thể kế thừa. Được bảo vệ cho phép nó được kế thừa nhưng vẫn không thể truy cập trực tiếp từ bên ngoài lớp. Lưu câu trả lời này

Làm cách nào để truy cập các thành viên riêng của một lớp PHP?

php sử dụng PhpPrivateAccess \MyClass; . $đóng cửa = \Đóng cửa. liên kết (hàm (MyClass $class) { return $class->property; }, null, MyClass. lớp); . "