Bir örneğin sınıfının bir arayüz uygulayıp uygulamadığını kontrol etmek?


148

Bir sınıf örneği verildiğinde, belirli bir arabirimi uygulayıp uygulamadığını belirlemek mümkün mü? Bildiğim kadarıyla, bunu doğrudan yapmak için yerleşik bir işlev yok. Hangi seçeneklerim var (varsa)?

Yanıtlar:


258
interface IInterface
{
}

class TheClass implements IInterface
{
}

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

"İnstanceof" operatörünü kullanabilirsiniz. Bunu kullanmak için, sol işlenen bir sınıf örneğidir ve sağ işlenen bir arabirimdir. Nesne belirli bir arabirimi uygularsa true değerini döndürür.


102

Gibi therefromhere işaret, kullanabilirsiniz class_implements(). Tıpkı Yansıma'da olduğu gibi, bu da sınıf adını dize olarak belirtmenize olanak tanır ve sınıfın bir örneğini gerektirmez:

interface IInterface
{
}

class TheClass implements IInterface
{
}

$interfaces = class_implements('TheClass');

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

class_implements() , SPL uzantısının bir parçasıdır.

Bkz. Http://php.net/manual/en/function.class-implements.php

Performans testleri

Bazı basit performans testleri her bir yaklaşımın maliyetini gösterir:

Bir nesnenin örneği verildi

Döngü dışında nesne yapımı (100.000 iterasyon)
 ____________________________________________
| class_implements | Yansıma | instanceOf |
| ------------------ | ------------ | ------------ |
| 140 ms | 290 ms | 35 ms |
'--------------------------------------------'

Döngü içinde nesne yapımı (100.000 iterasyon)
 ____________________________________________
| class_implements | Yansıma | instanceOf |
| ------------------ | ------------ | ------------ |
| 182 ms | 340 ms | 83 ms | Ucuz Oluşturucu
| 431 ms | 607 ms | 338 ms | Pahalı Yapıcı
'--------------------------------------------'

Yalnızca bir sınıf adı verildi

100.000 yineleme
 ____________________________________________
| class_implements | Yansıma | instanceOf |
| ------------------ | ------------ | ------------ |
| 149 ms | 295 ms | Yok |
'--------------------------------------------'

Pahalı __construct () nerede:

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

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

Bu testler bu basit koda dayanmaktadır .


56

nlaq instanceof, nesnenin bir arabirimi uygulayan bir sınıf örneği olup olmadığını sınamak için kullanılabileceğini belirtir.

Ancak instanceofbir sınıf türü ve bir arabirim arasında ayrım yapmaz. Nesnenin çağrılması gereken bir sınıf olup olmadığını bilmiyorsunuz IInterface.

Bunu daha ayrıntılı olarak test etmek için PHP'deki yansıma API'sını da kullanabilirsiniz:

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

Bkz. Http://php.net/manual/en/book.reflection.php


2
Bu "statik" sınıflarda kullanılabilir
Znarkus

6
Ayrıca bakınızclass_implements()
John Carter

@therefromhere: Teşekkürler, iyi bir ipucu. Bu SPL uzantısının bir parçası. Cevabım Reflection uzantısını kullandı.
Bill Karwin

3
Ad alanlarını kullanırsanız, aynı adla arabirimler ve sınıflar arasında bir belirsizlik olmaz ve instanceoftekrar güvenle kullanabilirsiniz .
grip

class_implements()Tam bir yansıma yapmak yerine class_implements ve ardından in_array'ı aramak daha hızlı olduğu için +1
Nickolaus

19

Sadece gelecekteki aramalara yardımcı olmak için is_subclass_of da iyi bir varyanttır (PHP 5.3.7+ için):

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

5

Aşağıdakileri de yapabilirsiniz

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

Arayüzü $objectSupposedToBeImplementinguygulamazsa kurtarılabilir bir hata verir YourInterface.


3

Güncelleme

is_a Fonksiyon alternatif olarak burada eksik.

Belirtilen yollardan hangisinin en yüksek performans gösterdiğini kontrol etmek için bazı performans testleri yaptım.

100.000'den fazla yineleme

      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% | ............................................

Farkı görmek "hissetmek" için bazı noktalar eklendi.

Bununla oluşturulan: https://3v4l.org/8Cog7

Sonuç

Kontrol edilecek bir nesneniz varsa instance of, kabul edilen cevapta belirtildiği gibi kullanın .

Eğer bir var sınıfını , kullanımını kontrol etmek is_a.

Bonus

Bir sınıfa sahip olmasını istediğiniz arabirime dayalı olarak başlatmak istediğinizde, kullanmak daha önceden hazırdır is_a. Yalnızca bir istisna vardır - kurucu boş olduğunda.

Misal: is_a(<className>, <interfaceName>, true);

Geri dönecek bool. "Üçüncü parametre allow_string " o sınıf isimleri kontrol etmenizi sağlar olmadan sınıfını başlatmasını.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.