Hướng dẫn what is the difference between trait and interface in php? - sự khác biệt giữa đặc điểm và giao diện trong php là gì?

Các câu trả lời khác đã làm một công việc tuyệt vời để giải thích sự khác biệt giữa các giao diện và đặc điểm. Tôi sẽ tập trung vào một ví dụ trong thế giới thực hữu ích, đặc biệt là chứng minh rằng các đặc điểm có thể sử dụng các biến thể hiện - cho phép bạn thêm hành vi vào một lớp với mã nồi hơi tối thiểu.

Một lần nữa, như được đề cập bởi những người khác, các đặc điểm kết hợp tốt với các giao diện, cho phép giao diện chỉ định hợp đồng hành vi và đặc điểm để thực hiện việc thực hiện.

Thêm khả năng xuất bản / đăng ký sự kiện vào một lớp có thể là một kịch bản phổ biến trong một số cơ sở mã. Có 3 giải pháp phổ biến:

  1. Xác định một lớp cơ sở với Pub/Sub Code, và sau đó các lớp muốn cung cấp các sự kiện có thể mở rộng nó để đạt được các khả năng.
  2. Xác định một lớp với Pub/Sub Code, và sau đó các lớp khác muốn cung cấp các sự kiện có thể sử dụng nó thông qua bố cục, xác định các phương thức của riêng chúng để bọc đối tượng được sáng tác, ủy quyền cho phương thức gọi cho nó.
  3. Xác định một đặc điểm với sự kiện Pub/Code Sub, và sau đó các lớp khác muốn cung cấp các sự kiện có thể use Đặc điểm, hay còn gọi là nhập khẩu, để đạt được các khả năng.

Mỗi công việc tốt như thế nào?

#1 không hoạt động tốt. Cho đến ngày bạn nhận ra bạn không thể mở rộng lớp cơ sở vì bạn đã mở rộng một thứ khác. Tôi sẽ không chỉ ra một ví dụ về điều này bởi vì rõ ràng việc sử dụng kế thừa như thế này là như thế nào.

#2 & #3 Cả hai đều hoạt động tốt. Tôi sẽ trình bày một ví dụ làm nổi bật một số khác biệt.

Đầu tiên, một số mã sẽ giống nhau giữa cả hai ví dụ:

Một giao diện

interface Observable {
    function addEventListener[$eventName, callable $listener];
    function removeEventListener[$eventName, callable $listener];
    function removeAllEventListeners[$eventName];
}

Và một số mã để chứng minh việc sử dụng:

$auction = new Auction[];

// Add a listener, so we know when we get a bid.
$auction->addEventListener['bid', function[$bidderName, $bidAmount]{
    echo "Got a bid of $bidAmount from $bidderName\n";
}];

// Mock some bids.
foreach [['Moe', 'Curly', 'Larry'] as $name] {
    $auction->addBid[$name, rand[]];
}

OK, bây giờ hãy cho thấy việc triển khai lớp Auction sẽ khác nhau như thế nào khi sử dụng các đặc điểm.

Đầu tiên, đây là cách số 2 [sử dụng thành phần] sẽ giống như:

class EventEmitter {
    private $eventListenersByName = [];

    function addEventListener[$eventName, callable $listener] {
        $this->eventListenersByName[$eventName][] = $listener;
    }

    function removeEventListener[$eventName, callable $listener] {
        $this->eventListenersByName[$eventName] = array_filter[$this->eventListenersByName[$eventName], function[$existingListener] use [$listener] {
            return $existingListener === $listener;
        }];
    }

    function removeAllEventListeners[$eventName] {
        $this->eventListenersByName[$eventName] = [];
    }

    function triggerEvent[$eventName, array $eventArgs] {
        foreach [$this->eventListenersByName[$eventName] as $listener] {
            call_user_func_array[$listener, $eventArgs];
        }
    }
}

class Auction implements Observable {
    private $eventEmitter;

    public function __construct[] {
        $this->eventEmitter = new EventEmitter[];
    }

    function addBid[$bidderName, $bidAmount] {
        $this->eventEmitter->triggerEvent['bid', [$bidderName, $bidAmount]];
    }

    function addEventListener[$eventName, callable $listener] {
        $this->eventEmitter->addEventListener[$eventName, $listener];
    }

    function removeEventListener[$eventName, callable $listener] {
        $this->eventEmitter->removeEventListener[$eventName, $listener];
    }

    function removeAllEventListeners[$eventName] {
        $this->eventEmitter->removeAllEventListeners[$eventName];
    }
}

Đây là cách số 3 [đặc điểm] sẽ giống như:

trait EventEmitterTrait {
    private $eventListenersByName = [];

    function addEventListener[$eventName, callable $listener] {
        $this->eventListenersByName[$eventName][] = $listener;
    }

    function removeEventListener[$eventName, callable $listener] {
        $this->eventListenersByName[$eventName] = array_filter[$this->eventListenersByName[$eventName], function[$existingListener] use [$listener] {
            return $existingListener === $listener;
        }];
    }

    function removeAllEventListeners[$eventName] {
        $this->eventListenersByName[$eventName] = [];
    }

    protected function triggerEvent[$eventName, array $eventArgs] {
        foreach [$this->eventListenersByName[$eventName] as $listener] {
            call_user_func_array[$listener, $eventArgs];
        }
    }
}

class Auction implements Observable {
    use EventEmitterTrait;

    function addBid[$bidderName, $bidAmount] {
        $this->triggerEvent['bid', [$bidderName, $bidAmount]];
    }
}

Lưu ý rằng mã bên trong EventEmitterTrait hoàn toàn giống với những gì bên trong lớp EventEmitter ngoại trừ tính trạng tuyên bố phương thức triggerEvent[] được bảo vệ. Vì vậy, sự khác biệt duy nhất bạn cần xem xét là việc thực hiện lớp Auction.the only difference you need to look at is the implementation of the Auction class.

Và sự khác biệt là lớn. Khi sử dụng sáng tác, chúng tôi có được một giải pháp tuyệt vời, cho phép chúng tôi sử dụng lại EventEmitter của chúng tôi bằng nhiều lớp như chúng tôi muốn. Nhưng, nhược điểm chính là chúng tôi có rất nhiều mã nồi hơi mà chúng tôi cần viết và duy trì bởi vì đối với mỗi phương thức được xác định trong giao diện

$auction = new Auction[];

// Add a listener, so we know when we get a bid.
$auction->addEventListener['bid', function[$bidderName, $bidAmount]{
    echo "Got a bid of $bidAmount from $bidderName\n";
}];

// Mock some bids.
foreach [['Moe', 'Curly', 'Larry'] as $name] {
    $auction->addBid[$name, rand[]];
}
1, chúng tôi cần thực hiện nó và viết mã Boing Boilerplate chỉ chuyển tiếp các đối số vào phương thức tương ứng Trong sáng tác của chúng tôi đối tượng EventEmitter. Sử dụng đặc điểm trong ví dụ này cho phép chúng tôi tránh điều đó, giúp chúng tôi giảm mã nồi hơi và cải thiện khả năng bảo trì.the trait in this example lets us avoid that, helping us reduce boilerplate code and improve maintainability.

Tuy nhiên, có thể có những lúc bạn không muốn lớp Auction của mình triển khai giao diện

$auction = new Auction[];

// Add a listener, so we know when we get a bid.
$auction->addEventListener['bid', function[$bidderName, $bidAmount]{
    echo "Got a bid of $bidAmount from $bidderName\n";
}];

// Mock some bids.
foreach [['Moe', 'Curly', 'Larry'] as $name] {
    $auction->addBid[$name, rand[]];
}
1 đầy đủ - có thể bạn chỉ muốn phơi bày 1 hoặc 2 phương thức, hoặc thậm chí có thể không có gì để bạn có thể xác định chữ ký phương thức của riêng mình. Trong trường hợp như vậy, bạn vẫn có thể thích phương pháp thành phần.

Nhưng, đặc điểm này rất hấp dẫn trong hầu hết các tình huống, đặc biệt là nếu giao diện có rất nhiều phương thức, điều này khiến bạn viết nhiều nồi hơi.

* Bạn thực sự có thể thực hiện cả hai - Xác định lớp EventEmitter trong trường hợp bạn muốn sử dụng nó theo thành phần và xác định tính trạng EventEmitterTrait, sử dụng triển khai lớp EventEmitter bên trong đặc điểm :]

Một đặc điểm trong PHP là gì?

Đặc điểm là một cơ chế để tái sử dụng mã trong các ngôn ngữ kế thừa duy nhất như PHP. Một đặc điểm nhằm giảm một số hạn chế của việc thừa kế bằng cách cho phép nhà phát triển sử dụng lại các bộ phương thức một cách tự do trong một số lớp độc lập sống trong các phân cấp lớp khác nhau.a mechanism for code reuse in single inheritance languages such as PHP. A Trait is intended to reduce some limitations of single inheritance by enabling a developer to reuse sets of methods freely in several independent classes living in different class hierarchies.

Sự khác biệt giữa kế thừa và giao diện trong PHP là gì?

Định nghĩa giao diện chỉ liên quan đến các hằng số.Một giao diện chứa các phương thức trừu tượng trong khi các lớp kế thừa chứa mã cho mỗi phương thức.Truy cập các nhà xác định được sử dụng trong một giao diện chỉ có thể được công khai. Conversely, While inheriting the class the members can be declared as constant and variable. An interface contains the abstract methods while inheriting classes contain code for each method. Access specifiers used in an interface can be only public.

Sự khác biệt giữa một đặc điểm và một lớp trừu tượng trong PHP là gì?

Đặc điểm hỗ trợ nhiều kế thừa.Abstract Lớp chỉ hỗ trợ kế thừa duy nhất.Đặc điểm có thể được thêm vào một thể hiện đối tượng.Lớp trừu tượng không thể được thêm vào một thể hiện đối tượng. Abstract Class supports single inheritance only. Trait can be added to an object instance. Abstract class cannot be added to an object instance.

Sự khác biệt giữa lớp và giao diện trong PHP là gì?

Sự khác biệt giữa các giao diện và các lớp trừu tượng là: các giao diện không thể có thuộc tính, trong khi các lớp trừu tượng có thể.Tất cả các phương thức giao diện phải được công khai, trong khi các phương thức lớp trừu tượng được công khai hoặc được bảo vệ.Interfaces cannot have properties, while abstract classes can. All interface methods must be public, while abstract class methods is public or protected.

Bài Viết Liên Quan

Chủ Đề