Sprawdzanie, czy klasa instancji implementuje interfejs?
Biorąc pod uwagę instancję klasy, czy jest możliwe określenie, czy implementuje ona konkretny interfejs? Z tego, co wiem, nie ma wbudowanej funkcji, aby to zrobić bezpośrednio. Jakie opcje mam (jeśli istnieją)?
6 answers
interface IInterface
{
}
class TheClass implements IInterface
{
}
$cls = new TheClass();
if ($cls instanceof IInterface) {
echo "yes";
}
Możesz użyć operatora "instanceof". Aby go użyć, lewy operand jest instancją klasy, a prawy operand jest interfejsem. Zwraca true, jeśli obiekt implementuje określony interfejs.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-14 11:33:51
Jak wskazuje stąd , możesz użyć class_implements()
. Podobnie jak w przypadku Reflection, pozwala to określić nazwę klasy jako łańcuch znaków i nie wymaga wystąpienia klasy:
interface IInterface
{
}
class TheClass implements IInterface
{
}
$interfaces = class_implements('TheClass');
if (isset($interfaces['IInterface'])) {
echo "Yes!";
}
class_implements()
jest częścią rozszerzenia SPL.
Zobacz: http://php.net/manual/en/function.class-implements.php
Testy Wydajnościowe
Niektóre proste testy wydajności pokazują koszty każdego podejścia:
Dana instancja obiekt
Object construction outside the loop (100,000 iterations) ____________________________________________ | class_implements | Reflection | instanceOf | |------------------|------------|------------| | 140 ms | 290 ms | 35 ms | '--------------------------------------------' Object construction inside the loop (100,000 iterations) ____________________________________________ | class_implements | Reflection | instanceOf | |------------------|------------|------------| | 182 ms | 340 ms | 83 ms | Cheap Constructor | 431 ms | 607 ms | 338 ms | Expensive Constructor '--------------------------------------------'
Podano tylko nazwę klasy
100,000 iterations ____________________________________________ | class_implements | Reflection | instanceOf | |------------------|------------|------------| | 149 ms | 295 ms | N/A | '--------------------------------------------'
Gdzie drogie _ _ construct () jest:
public function __construct() {
$tmp = array(
'foo' => 'bar',
'this' => 'that'
);
$in = in_array('those', $tmp);
}
Te testy są oparte na tym prostym kodzie .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:23
Nlaq wskazuje, że instanceof
może być użyty do sprawdzenia, czy obiekt jest instancją klasy implementującej interfejs.
Ale instanceof
nie odróżnia typu klasy od interfejsu. Nie wiesz, czy obiekt jest klasą , która nazywa się IInterface
.
Możesz również użyć API reflection w PHP, aby przetestować to dokładniej:
$class = new ReflectionClass('TheClass');
if ($class->implementsInterface('IInterface'))
{
print "Yep!\n";
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-17 02:14:09
Aby pomóc przyszłym wyszukiwaniom is_subclass_of jest również dobrym wariantem (dla PHP 5.3.7+):
if (is_subclass_of($my_class_instance, 'ISomeInterfaceName')){
echo 'I can do it!';
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-12 12:45:48
Update
The is_a
funkcja nie jest tutaj dostępna jako alternatywa.
Zrobiłem kilka testów wydajności, aby sprawdzić, który z podanych sposobów jest najbardziej wydajny.
Wyniki ponad 100k iteracji
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% | ............................................
Dodano kilka kropek, aby faktycznie "poczuć" zobaczyć różnicę.
Wygenerowane przez to: https://3v4l.org/8Cog7
Podsumowanie
Jeśli masz obiekt do sprawdzenia, użyj instance of
Jak wspomniano w akceptowanym odpowiedz.
Jeśli masz klasę do sprawdzenia, użyj is_a
.
Bonus
Biorąc pod uwagę przypadek, w którym chcesz utworzyć instancję klasy na podstawie wymaganego interfejsu, bardziej preformantowe jest użycie is_a
. Jest tylko jeden wyjątek - gdy konstruktor jest pusty.
Przykład:
is_a(<className>, <interfaceName>, true);
Zwróci bool
. Trzeci parametr " allow_string" pozwala na sprawdzenie nazw klas bez tworzenia instancji klasy.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55
Możesz również wykonać następujące czynności]}
public function yourMethod(YourInterface $objectSupposedToBeImplementing) {
//.....
}
Spowoduje błąd, który można odzyskać, jeśli $objectSupposedToBeImplementing
nie zaimplementuje interfejsu YourInterface
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-31 09:22:01