Sự khác biệt giữa self :: $ bar và static :: $ bar trong PHP là gì?


125

Sự khác biệt giữa cách sử dụng selfstatictrong ví dụ dưới đây là gì?

class Foo
{
    protected static $bar = 1234;

    public static function instance()
    {
        echo self::$bar;
        echo "\n";
        echo static::$bar;
    }

}

Foo::instance();

sản xuất

1234
1234

2
@deceze: Đó là một câu hỏi tương tự, nhưng nó không phải là một câu hỏi trùng lặp. Câu hỏi này hỏi về việc sử dụng các từ khóa có thuộc tính, trong khi câu hỏi về việc sử dụng chúng với các hàm tạo.
BoltClock

Câu trả lời:


191

Khi bạn sử dụng selfđể chỉ một thành viên trong lớp, bạn đang đề cập đến lớp mà bạn sử dụng từ khóa trong đó. Trong trường hợp này, Foolớp của bạn định nghĩa một thuộc tính tĩnh được bảo vệ được gọi là $bar. Khi bạn sử dụng selftrong Foolớp để tham chiếu đến thuộc tính, bạn đang tham chiếu đến cùng một lớp.

Do đó, nếu bạn đã cố gắng sử dụng self::$barở nơi khác trong Foolớp của mình nhưng bạn có một Barlớp có giá trị khác cho thuộc tính, nó sẽ sử dụng Foo::$barthay vì Bar::$bar, có thể không phải như những gì bạn dự định:

class Foo
{
    protected static $bar = 1234;
}

class Bar extends Foo
{
    protected static $bar = 4321;
}

Khi bạn gọi một phương thức qua static, bạn đang gọi một tính năng được gọi là liên kết tĩnh muộn (được giới thiệu trong PHP 5.3).

Trong trường hợp trên, việc sử dụng selfsẽ dẫn đến Foo::$bar(1234). Và việc sử dụng staticsẽ dẫn đến Bar::$bar(4321) vì với static, trình thông dịch sẽ tính đến việc khai báo lại trong Barlớp trong thời gian chạy.

Bạn thường sử dụng các liên kết tĩnh trễ cho các phương thức hoặc thậm chí chính lớp đó, thay vì các thuộc tính, vì bạn không thường khai báo lại các thuộc tính trong các lớp con; staticCó thể tìm thấy một ví dụ về việc sử dụng từ khóa để gọi một hàm tạo bị giới hạn cuối trong câu hỏi liên quan này: New self so với new static

Tuy nhiên, điều đó cũng không loại trừ việc sử dụng staticvới các thuộc tính.


Bạn có thể rất dễ khai báo lại trong lớp con, lớp cha có thể là một giá trị mặc định mà lớp con sử dụng trừ khi chúng khai báo lại. Nếu bạn ở trong lớp cha, tôi đoán sẽ an toàn khi sử dụng self ::, và nếu ở lớp con, bạn có thể đưa ra một đối số để sử dụng một trong hai, nhưng self :: cũng sẽ hoạt động nếu bạn không mong đợi khai lại bao giờ.
Andrew

3
truy cập phpfiddle.org và chạy cái này<?php class Foo { public static $bar = 1234; public static function a( ) { echo 'static'.static::$bar; echo 'self'.self::$bar; } } class Bar extends Foo { public static $bar = 4321; } (new Bar())->a(); ?>
Yevgeniy Afanasyev

2
Cách diễn đạt của hai đoạn đầu là khó hiểu, có một đại từ không rõ ràng, "nó", và cũng bị ám chỉ lại, vì các đoạn sau giải thích cùng một thông tin rõ ràng hơn. Tôi đề nghị thay hai đoạn đầu bằng đoạn sau bắt đầu bằng "Trong tình huống trên" lên trên cùng. Bằng cách đó, điểm mấu chốt, câu trả lời cần thiết nằm ở đầu. Nó rõ ràng và dễ làm theo.
ahnbizcad

Một cách khác để suy nghĩ về điều này : self::$abc, khi được sử dụng bên trong class Foocũng giống như cách nói Foo::$abc. Nó sẽ không bị ảnh hưởng bởi bất kỳ khai báo lại nào $abctrong một lớp con. AFAIK, lý do duy nhất để sử dụng selflà viết tắt, để tránh sử dụng tên lớp Foo, có thể dài hơn. [Điều đó cũng có nghĩa là bạn có thể thay đổi tên lớp mà không cần thay đổi tất cả những chỗ đó - nhưng đó không phải là lý do nhiều IMHO.] (Sự lựa chọn tên của PHP là không may, và có vẻ ngược; "static" là tên có thể thay đổi - mà đối lập với nghĩa thông tục của từ "tĩnh" trong ngôn ngữ tự nhiên.)
ToolmakerSteve

4

Như đã đề cập, một trong những điểm khác biệt chính là staticcho phép các ràng buộc tĩnh trễ. Một trong những kịch bản hữu ích nhất mà tôi tìm thấy là để tạo các lớp Cơ sở cho Lớp Singleton:

class A { // Base Class
    protected static $name = '';
    protected static function getName() {
        return static::$name;
    }
}
class B extends A {
    protected static $name = 'MyCustomNameB';
}
class C extends A {
    protected static $name = 'MyCustomNameC';
}

echo B::getName(); // MyCustomNameB
echo C::getName(); // MyCustomNameC

Sử dụng return static::$nametrong lớp Cơ sở sẽ trả về những gì đã được đính kèm tĩnh khi nó được mở rộng. Nếu bạn đã sử dụng return self::$namethì B::getName()sẽ trả về một chuỗi trống vì đó là những gì được khai báo trong lớp Cơ sở.


0

Với selfcuộc gọi:

class Foo
{
    protected static $var = 123;
    
    public function getVar()
    {
        return self::$var;
    }
}

class Bar extends Foo
{
    protected static $var = 234;
}

// Displays: "123"
echo (new Bar)->getVar();

Bạn có thể thấy ở trên, mặc dù chúng ta đã ghi đè lớp $varcủa Barmình, nó vẫn trả về 123, bởi vì chúng ta đã yêu cầu PHP một cách rõ ràng về selfbiến, thay vào đó nó sẽ yêu cầu Foobiến s.

Bây giờ nếu chúng ta hoán đổi cuộc gọi với static, thay vào đó chúng ta sẽ nhận được Bargiá trị ghi đè của s:

Với staticcuộc gọi:

class Foo
{
    protected static $var = 123;
    
    public function getVar()
    {
        return static::$var;
    }
}

class Bar extends Foo
{
    protected static $var = 234;
}

// Displays: "234"
echo (new Bar)->getVar();
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.