Kiểm tra nếu một lớp của một cá thể thực hiện một giao diện?


148

Cho một thể hiện của lớp, có thể xác định nếu nó thực hiện một giao diện cụ thể không? Theo tôi biết, không có chức năng tích hợp để thực hiện việc này trực tiếp. Tôi có những lựa chọn nào (nếu có)?

Câu trả lời:


258
interface IInterface
{
}

class TheClass implements IInterface
{
}

$cls = new TheClass();
if ($cls instanceof IInterface) {
    echo "yes";
}

Bạn có thể sử dụng toán tử "instanceof". Để sử dụng nó, toán hạng bên trái là một thể hiện của lớp và toán hạng bên phải là một giao diện. Nó trả về true nếu đối tượng thực hiện một giao diện cụ thể.


102

Như therefromhere chỉ ra, bạn có thể sử dụng class_implements(). Cũng giống như với Reflection, điều này cho phép bạn chỉ định tên lớp là một chuỗi và không yêu cầu một thể hiện của lớp:

interface IInterface
{
}

class TheClass implements IInterface
{
}

$interfaces = class_implements('TheClass');

if (isset($interfaces['IInterface'])) {
    echo "Yes!";
}

class_implements() là một phần của phần mở rộng SPL.

Xem: http://php.net/manual/en/feft.group-implements.php

Kiểm tra hiệu năng

Một số thử nghiệm hiệu suất đơn giản cho thấy chi phí của từng phương pháp:

Cho một thể hiện của một đối tượng

Xây dựng đối tượng bên ngoài vòng lặp (100.000 lần lặp)
 Giới thiệu
| class_implements | Phản ánh | dụOf |
| ------------------ | ------------ | ------------ |
| 140 ms | 290 ms | 35 ms |
'--------------------------------------------'

Xây dựng đối tượng bên trong vòng lặp (100.000 lần lặp)
 Giới thiệu
| class_implements | Phản ánh | dụOf |
| ------------------ | ------------ | ------------ |
| 182 ms | 340 ms | 83 ms | Xây dựng giá rẻ
| 431 ms | 607 ms | 338 ms | Xây dựng đắt tiền
'--------------------------------------------'

Chỉ được cung cấp một tên lớp

100.000 lần lặp
 Giới thiệu
| class_implements | Phản ánh | dụOf |
| ------------------ | ------------ | ------------ |
| 149 ms | 295 ms | Không có |
'--------------------------------------------'

Trong đó __construct () đắt tiền là:

public function __construct() {
    $tmp = array(
        'foo' => 'bar',
        'this' => 'that'
    );  

    $in = in_array('those', $tmp);
}

Các xét nghiệm này dựa trên mã đơn giản này .


56

nlaq chỉ ra rằng instanceofcó thể được sử dụng để kiểm tra nếu đối tượng là một thể hiện của một lớp thực hiện một giao diện.

Nhưng instanceofkhông phân biệt giữa một loại lớp và một giao diện. Bạn không biết nếu đối tượng là một lớp tình cờ được gọi IInterface.

Bạn cũng có thể sử dụng API phản chiếu trong PHP để kiểm tra điều này cụ thể hơn:

$class = new ReflectionClass('TheClass');
if ($class->implementsInterface('IInterface'))
{
  print "Yep!\n";
}

Xem http://php.net/manual/en/book.reflection.php


2
Điều này có thể được sử dụng trên các lớp "tĩnh"
Znarkus


@therefromhere: Cảm ơn, mẹo tốt. Đó là một phần của phần mở rộng SPL. Câu trả lời của tôi đã sử dụng phần mở rộng Reflection.
Bill Karwin

3
Nếu bạn sử dụng các không gian tên thì sẽ không có sự mơ hồ giữa các giao diện và các lớp có cùng tên và bạn có thể sử dụng instanceoflại một cách an toàn .
cúm

+1 class_implements()vì rõ ràng nhanh hơn để gọi class_implements và sau đó là in_array, thay vì thực hiện một phản ánh hoàn chỉnh
Nickolaus 17/03/17

19

Chỉ để giúp các tìm kiếm trong tương lai is_subgroup_of cũng là một biến thể tốt (đối với PHP 5.3.7+):

if (is_subclass_of($my_class_instance, 'ISomeInterfaceName')){
    echo 'I can do it!';
}

5

Bạn cũng có thể làm như sau

public function yourMethod(YourInterface $objectSupposedToBeImplementing) {
   //.....
}

Nó sẽ đưa ra một lỗi có thể phục hồi nếu $objectSupposedToBeImplementingkhông thực hiện YourInterfaceGiao diện.


3

Cập nhật

Các is_a chức năng bị thiếu ở đây là thay thế.

Tôi đã thực hiện một số bài kiểm tra hiệu suất để kiểm tra xem những cách nào được nêu là hiệu quả nhất.

Kết quả hơn 100 nghìn lần lặp

      instanceof [object] took   7.67 ms | +  0% | ..........
            is_a [object] took  12.30 ms | + 60% | ................
             is_a [class] took  17.43 ms | +127% | ......................
class_implements [object] took  28.37 ms | +270% | ....................................
       reflection [class] took  34.17 ms | +346% | ............................................

Đã thêm một số dấu chấm để thực sự "cảm thấy" thấy sự khác biệt.

Được tạo bởi điều này: https://3v4l.org/8Cog7

Phần kết luận

Trong trường hợp bạn có một đối tượng để kiểm tra, hãy sử dụng instance ofnhư được đề cập trong câu trả lời được chấp nhận.

Trong trường hợp bạn có một lớp để kiểm tra, sử dụng is_a.

Tặng kem

Với trường hợp bạn muốn khởi tạo một lớp dựa trên một giao diện mà bạn yêu cầu nó phải có, nó sẽ được sử dụng nhiều hơn is_a. Chỉ có một ngoại lệ - khi hàm tạo trống.

Thí dụ: is_a(<className>, <interfaceName>, true);

Nó sẽ trở lại bool. Tham số thứ ba " allow_ chuỗi " cho phép nó kiểm tra tên lớp mà không cần khởi tạo lớp.

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.