Bản thân mới so với tĩnh mới


513

Tôi đang chuyển đổi thư viện PHP 5.3 để hoạt động trên PHP 5.2. Vấn đề chính cản trở tôi là việc sử dụng liên kết tĩnh muộn như thế nào return new static($options);, nếu tôi chuyển đổi nó thành return new self($options)tôi sẽ nhận được kết quả tương tự?

Sự khác biệt giữa new selfvà là new staticgì?

Câu trả lời:


890

Tôi sẽ nhận được kết quả tương tự?

Không hẳn vậy. Tuy nhiên, tôi không biết cách giải quyết cho PHP 5.2.

Sự khác biệt giữa new selfvà là new staticgì?

selfđề cập đến cùng một lớp trong đó newtừ khóa thực sự được viết.

static, trong các ràng buộc tĩnh muộn của PHP 5.3, đề cập đến bất kỳ lớp nào trong hệ thống phân cấp mà bạn gọi là phương thức trên.

Trong ví dụ sau, Bkế thừa cả hai phương thức từ A. Lệnh selfgọi bị ràng buộc Abởi vì nó được định nghĩa trong Aviệc thực hiện phương thức đầu tiên, trong khi đó staticbị ràng buộc với lớp được gọi (cũng xem get_called_class()).

class A {
    public static function get_self() {
        return new self();
    }

    public static function get_static() {
        return new static();
    }
}

class B extends A {}

echo get_class(B::get_self());  // A
echo get_class(B::get_static()); // B
echo get_class(A::get_self()); // A
echo get_class(A::get_static()); // A

có ý nghĩa. Tôi nghĩ rằng đặt cược tốt nhất là chuyển tên lớp cho hàm đang sử dụng liên kết tĩnh muộn và sau đó trả về $ className mới (tùy chọn $);
Mike

12
Bạn không phải "vượt qua" tên lớp, bạn luôn có thể làm get_called_class(), điều này thực sự giống như __CLASS__, nhưng tương thích LSB.
Shadowhand

7
get_called_group không tồn tại trong <PHP5.3. Do đó, nếu bạn muốn lấy tên lớp của đối tượng được khởi tạo trong PHP5.2 Hàm này không giúp ích gì khi cố gắng chuyển đổi thư viện từ PHP 5.3 sang PHP 5.2
txwikinger

2
Hàm được gọi là self :: theFunction () hoạt động như "Tôi sẽ thực thi trong ngữ cảnh của lớp mà tôi thuộc về thể chất." và hàm được gọi là static :: theFunction () hoạt động như "Tôi sẽ thực thi trong ngữ cảnh của lớp đã được thế giới bên ngoài thực sự gọi". (Giả sử kịch bản thừa kế). Cảm ơn
Shubhranshu

2
Trong đầu, tôi chỉ lấy bất cứ thứ gì trực quan, và làm cho nó ngược lại. Bạn sẽ nghĩ dựa trên việc đặt tên, selfsẽ tự trả về và staticsẽ trả lại thứ gì đó không thể bị ghi đè ... Nhưng lo và coi đó là điều ngược lại. Tôi không bao giờ hết ấn tượng bởi cách đặt tên, quy ước và phong cách tổng thể của PHP. -_-
ahnbizcad

23

Nếu phương thức của mã này không tĩnh, bạn có thể xử lý xung quanh trong 5.2 bằng cách sử dụng get_class($this).

class A {
    public function create1() {
        $class = get_class($this);
        return new $class();
    }
    public function create2() {
        return new static();
    }
}

class B extends A {

}

$b = new B();
var_dump(get_class($b->create1()), get_class($b->create2()));

Kết quả:

string(1) "B"
string(1) "B"

17
Nếu phương thức không tĩnh thì các ràng buộc tĩnh muộn trở nên hoàn toàn không liên quan.
BoltClock

1
Ví dụ: bạn có thể sử dụng nó trong phương thức "sao chép", trong đó đối tượng được sao chép mà không sử dụng clone, mà chỉ bằng cách tạo lại và thiết lập các thuộc tính. $copy = new static(); $copy->set($this->get()); return $copy;
Marius Balčytis

9
@BoltClock Chắc chắn không? Nếu bạn đang gọi một phương thức tĩnh được ghi đè từ bên trong một phương thức thể hiện của một lớp con, thì sự lựa chọn của bạn self::hoặc static::sẽ ảnh hưởng đến việc sử dụng phiên bản của lớp cơ sở hoặc lớp con của phương thức tĩnh đó. Trong trường hợp không có lý do nào đó để nghĩ rằng một tình huống như vậy xảy ra vốn chỉ ra thực tiễn xấu (và tôi không thấy bất kỳ lý do nào tại sao lại như vậy), sự lựa chọn giữa self::static::có liên quan trong các phương pháp không tĩnh như trong phương pháp tĩnh. Tôi đã hiểu nhầm ý kiến ​​của bạn, hay chỉ một người trong chúng ta sai?
Mark Amery

4
@Mark Amery: Hmm, tôi không nghĩ về điều đó. Bạn hoàn toàn đúng. Tôi đã giả định rằng không có phương thức tĩnh nào sẽ được gọi trong phương thức cá thể được đề cập, nhưng dựa trên ví dụ của bạn, tôi có thể thấy đó sẽ là một giả định rất ngây thơ.
BoltClock


7

Ngoài câu trả lời của người khác:

static :: sẽ được tính bằng thông tin thời gian chạy.

Điều đó có nghĩa là bạn không thể sử dụng static::trong một thuộc tính lớp vì các giá trị thuộc tính:

Phải có thể được đánh giá tại thời điểm biên dịch và không được phụ thuộc vào thông tin thời gian chạy.

class Foo {
    public $name = static::class;

}

$Foo = new Foo;
echo $Foo->name; // Fatal error

Sử dụng self::

class Foo {
    public $name = self::class;

}
$Foo = new Foo;
echo $Foo->name; // Foo

Xin lưu ý rằng nhận xét lỗi nghiêm trọng trong mã tôi đã tạo không cho biết lỗi xảy ra ở đâu, lỗi xảy ra trước đó trước khi đối tượng được khởi tạo như @Grapestain được đề cập trong các nhận xét


4
Lưu ý lỗi được ném trên dòng 2 public $name = static::class;, không phải trên dòng 7, như ví dụ đề xuất. Lỗi nói: "static :: class không thể được sử dụng để phân giải tên lớp thời gian biên dịch", điều này cho thấy vấn đề không phải là nơi bạn cố gắng truy cập vào trường $ name, mà trước đó, trong quá trình biên dịch của lớp PHP. Dòng 7 (hoặc 6) sẽ không đạt được trong ví dụ đầu tiên.
sbnc.eu

@Grapestain Nhận xét tôi đưa ra trong ví dụ là hiển thị kết quả cuối cùng và không cho biết lỗi thực sự xảy ra ở đâu. Nhưng dù sao cũng cảm ơn vì đã chỉ ra điều đó.
Mưa

Đúng vậy, tôi không có ý chỉ trích, chỉ làm rõ điều gì làm tôi bối rối trước với hy vọng nó có thể giúp đỡ người khác. Ví dụ hữu ích nào!
sbnc.eu
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.