Chính xác thì các ràng buộc tĩnh muộn trong PHP là gì?


Câu trả lời:


197

Bạn chắc chắn cần phải đọc các ràng buộc tĩnh muộn trong hướng dẫn sử dụng PHP. Tuy nhiên, tôi sẽ cố gắng cung cấp cho bạn một bản tóm tắt nhanh chóng.

Về cơ bản, nó đi sâu vào thực tế là selftừ khóa không tuân theo các quy tắc thừa kế tương tự. selfluôn luôn giải quyết lớp mà nó được sử dụng. Điều này có nghĩa là nếu bạn tạo một phương thức trong lớp cha và gọi nó từ lớp con, selfsẽ không tham chiếu đến đứa trẻ như bạn mong đợi.

Liên kết tĩnh muộn giới thiệu một cách sử dụng mới cho statictừ khóa, giải quyết thiếu sót đặc biệt này. Khi bạn sử dụng static, nó đại diện cho lớp nơi bạn sử dụng lần đầu tiên, nghĩa là. nó 'liên kết' với lớp thời gian chạy.

Đó là hai khái niệm cơ bản đằng sau nó. Cách self, parentstatichoạt động khi staticlà trong vở kịch có thể tinh tế, vì vậy thay vì đi vào chi tiết hơn, tôi muốn khuyên bạn nghiên cứu các ví dụ trang hướng dẫn. Khi bạn hiểu những điều cơ bản của từng từ khóa, các ví dụ khá cần thiết để xem bạn sẽ nhận được loại kết quả nào.


tôi thấy bài viết này thực sự hữu ích và mô tả, hãy xem nó [link] ( techflirt.com/tutorials/oop-in-php/late-static-binding.html )
Sadegh Shaikhi

"... selftừ khóa không tuân theo quy tắc thừa kế. selfLuôn giải quyết theo lớp mà nó được sử dụng." - Điều đó không có nghĩa là bạn không thể gọi phương thức tĩnh của cha mẹ từ một đối tượng con thông qua self, giống như với các phương thức không tĩnh. Bạn có thể có nghĩa là đúng, nhưng bạn nên diễn đạt lại. Tất cả chỉ thực sự quan trọng khi trẻ em có tên thành viên giống hệt nhau vì sau đó bạn có thể quyết định nên tham khảo cái nào bằng cách sử dụng static::thay thế.
Danman

81

Từ PHP: Ràng buộc tĩnh muộn - Hướng dẫn :

Kể từ phiên bản PHP 5.3.0, PHP triển khai một tính năng gọi là liên kết tĩnh muộn có thể được sử dụng để tham chiếu lớp được gọi trong bối cảnh kế thừa tĩnh.

Liên kết tĩnh muộn cố gắng giải quyết giới hạn đó bằng cách giới thiệu một từ khóa tham chiếu lớp được gọi ban đầu khi chạy. ... Nó đã được quyết định không giới thiệu một từ khóa mới, mà là sử dụng staticđã được bảo lưu.

Hãy xem một ví dụ:

<?php
    class Car
    {
        public static function run()
        {
            return static::getName();
        }

        private static function getName()
        {
            return 'Car';
        }
    }

    class Toyota extends Car
    {
        public static function getName()
        {
            return 'Toyota';
        }
    }

    echo Car::run(); // Output: Car
    echo Toyota::run(); // Output: Toyota
?>

Các ràng buộc tĩnh muộn hoạt động bằng cách lưu trữ lớp có tên trong "cuộc gọi không chuyển tiếp" cuối cùng. Trong trường hợp gọi phương thức tĩnh, đây là lớp được đặt tên rõ ràng (thường là lớp bên trái ::toán tử); trong trường hợp gọi phương thức không tĩnh, nó là lớp của đối tượng. Một "cuộc gọi chuyển tiếp" là một trong những tĩnh được giới thiệu bởi self::, parent::, static::, hoặc, nếu đi lên trong hệ thống phân cấp lớp, forward_static_call(). Hàm này get_called_class()có thể được sử dụng để truy xuất một chuỗi có tên của lớp được gọi và static::giới thiệu phạm vi của nó.


1
Bài đăng này là ~ 80% bản sao nguyên văn của bài viết php.net mà không cần đánh dấu trích dẫn.
WoodrowShigeru

22

Không có hành vi rất rõ ràng:

Đoạn mã sau tạo ra 'alphabeta'.

class alpha {

    function classname(){
        return __CLASS__;
    }

    function selfname(){
        return self::classname();
    }

    function staticname(){
        return static::classname();
    }
}

class beta extends alpha {

    function classname(){
        return __CLASS__;
    }
}

$beta = new beta();
echo $beta->selfname(); // Output: alpha
echo $beta->staticname(); // Output: beta

Tuy nhiên, nếu chúng ta xóa khai báo của hàm classname khỏi lớp beta, chúng ta sẽ nhận được 'alphaalpha'.


1
Rất đẹp. Điều tương tự được hiển thị trong hướng dẫn PHP, nhưng điều này rõ ràng hơn nhiều. Để tham khảo: php.net/manual/en/lingu.oop5.late-static-bindings.php (xem ví dụ 4)
musicin3d

11

Tôi đang trích dẫn từ cuốn sách: "PHP Master viết mã tiên tiến".

Liên kết tĩnh muộn là một tính năng được giới thiệu với php 5.3. Nó cho phép chúng ta kế thừa các phương thức tĩnh từ một lớp cha và tham chiếu lớp con được gọi.

Điều này có nghĩa là bạn có thể có một lớp trừu tượng với các phương thức tĩnh và tham chiếu các triển khai cụ thể của lớp con bằng cách sử dụng ký hiệu static :: method () thay vì self :: method ().

Vui lòng xem tài liệu php chính thức: http://php.net/manual/en/lingu.oop5.late-static-bindings.php


Cách rõ ràng nhất để giải thích Binding tĩnh muộn là với một ví dụ đơn giản. Hãy xem hai định nghĩa lớp dưới đây và đọc tiếp.

class Vehicle {
    public static function invokeDriveByStatic() {
        return static::drive(); // Late Static Binding
    }
    public static function invokeStopBySelf() {
        return self::stop(); // NOT Late Static Binding
    }
    private static function drive(){
        return "I'm driving a VEHICLE";
    }
    private static function stop(){
        return "I'm stopping a VEHICLE";
    }
}

class Car extends Vehicle  {
    protected static function drive(){
        return "I'm driving a CAR";
    }
    private static function stop(){
        return "I'm stopping a CAR";
    }
}

Chúng tôi thấy Lớp phụ huynh (Xe cộ) và Lớp trẻ em (Xe hơi). Lớp Phụ huynh có 2 phương thức chung:

  • invokeDriveByStatic
  • invokeStopBySelf

Lớp Phụ huynh cũng có 2 phương thức riêng:

  • drive
  • stop

Lớp con ghi đè 2 phương thức:

  • drive
  • stop

Bây giờ hãy gọi các phương thức công khai:

  • invokeDriveByStatic
  • invokeStopBySelf

Hãy tự hỏi: Lớp nào gọi invokeDriveByStatic/ invokeStopBySelf? Lớp Phụ huynh hay Trẻ em?

Hãy xem bên dưới:

// This is NOT Late Static Binding
// Parent class invokes from Parent. In this case Vehicle.
echo Vehicle::invokeDriveByStatic(); // I'm driving a VEHICLE
echo Vehicle::invokeStopBySelf(); // I'm stopping a VEHICLE

// !!! This is Late Static Binding !!!!
// Child class invokes an inherited method from Parent.
// Child class = Car, Inherited method = invokeDriveByStatic().
// The inherited method invokes a method that is overridden by the Child class.
// Overridden method = drive()
echo Car::invokeDriveByStatic(); // I'm driving a CAR

// This is NOT Late Static Binding
// Child class invokes an inherited method from Parent.
// The inherited method invokes a method inside the Vehicle context.
echo Car::invokeStopBySelf(); // I'm stopping a VEHICLE

Các statictừ khóa được sử dụng trong một mẫu thiết kế Singleton. Xem liên kết: https://refactoring.guru/design-potypes/singleton/php/example


7

Ví dụ đơn giản nhất để thể hiện sự khác biệt.
Lưu ý, tự :: $ c

class A
{
    static $c = 7;

    public static function getVal()
    {
        return self::$c;
    }
}

class B extends A
{
    static $c = 8;
}

B::getVal(); // 7

Liên kết tĩnh muộn, lưu ý tĩnh :: $ c

class A
{
    static $c = 7;

    public static function getVal()
    {
        return static::$c;
    }
}

class B extends A
{
    static $c = 8;
}

B::getVal(); // 8

4

Ví dụ:

abstract class Builder {
    public static function build() {
        return new static;
    }
}

class Member extends Builder {
    public function who_am_i() {
         echo 'Member';
    }
}

Member::build()->who_am_i();

4

Nhìn vào nó từ một "tại sao tôi sẽ sử dụng cái này?" phối cảnh, về cơ bản, đó là một cách để thay đổi bối cảnh mà phương thức tĩnh đang được diễn giải / chạy.

Với self, bối cảnh là nơi bạn xác định phương thức ban đầu. Với static, đó là người bạn gọi nó từ.


1

Ngoài ra, xem nếu bạn cập nhật các biến tĩnh trong các lớp con. Tôi tìm thấy kết quả bất ngờ này (phần nào) khi con B cập nhật con C:

class A{
    protected static $things;
}

class B extends A {
    public static function things(){
        static::$things[1] = 'Thing B';
        return static::$things; 
    }
}

class C extends A{
    public static function things(){
        static::$things[2] = 'Thing C';
        return static::$things;        
    }
}

print_r(C::things());
// Array (
//   [2] => Thing C
// )

B::things();

print_r(C::things()); 
// Array (
//    [2] => Thing C
//    [1] => Thing B
// )

Bạn có thể sửa nó bằng cách khai báo cùng một biến trong mỗi lớp con, ví dụ:

class C extends A{
    protected static $things; // add this and B will not interfere!

    public static function things(){
        static::$things[2] = 'Thing C';
        return static::$things;        
    }
}
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.