【问题标题】:PHP: how to get a list of classes that implement certain interface?PHP:如何获取实现特定接口的类列表?
【发布时间】:2011-04-28 23:16:19
【问题描述】:

我有一个界面

interface IModule {
    public function Install();
}

以及一些实现这个接口的类

class Module1 implements IModule {
    public function Install() {
        return true;
    }
}

class Module2 implements IModule {
    public function Install() {
        return true;
    }
}

...

class ModuleN implements IModule {
    public function Install() {
        return true;
    }
}

如何获取实现该接口的所有类的列表? 我想用 PHP 得到这个列表。

【问题讨论】:

  • 您可能应该澄清您是想在 PHP 中获取列表,还是只想生成这样的列表以用于文档等目的。

标签: php oop class


【解决方案1】:

你不需要反射。你可以简单地使用

用法

in_array('InterfaceName', class_implements('className'));

示例 1 - 回显所有实现迭代器接口的类

foreach (get_declared_classes() as $className) {
    if (in_array('Iterator', class_implements($className))) {
        echo $className, PHP_EOL;
    }
}

示例 2 - 返回实现迭代器接口的所有类的数组

print_r(
    array_filter(
        get_declared_classes(), 
        function ($className) {
            return in_array('Iterator', class_implements($className));
        }
    )
);

第二个例子需要 PHP5.3,因为回调是一个匿名函数。

【讨论】:

  • 如果你把它包装在一个函数上,并且使用 "::class" 是行不通的:phpfiddle.org/main/code/bvf8-izy6
  • 可以使用is_subclass_of($className, $interfaceName) 代替in_array()class_implements()
【解决方案2】:

您可以使用 PHP 的 ReflectionClass::implementsInterfaceget_declared_classes 函数来完成此操作:

$classes = get_declared_classes();
$implementsIModule = array();
foreach($classes as $klass) {
   $reflect = new ReflectionClass($klass);
   if($reflect->implementsInterface('IModule')) 
      $implementsIModule[] = $klass;
}

【讨论】:

  • 注意:如果您通过 __autoload 加载 IModules,这将不起作用。但是+1。
  • 迟到了 7 年的评论,但这里有一个示例,说明如何使用 Composers 自动加载中的文件来确保每次都会加载某些特定文件并可以使用 get_declared_classes:stackoverflow.com/a/18671530/143279
  • 这里所有答案的全部问题是get_declared_classes()。几乎没有在运行代码之前声明所有类的情况。
【解决方案3】:

通用解决方案:

function getImplementingClasses( $interfaceName ) {
    return array_filter(
        get_declared_classes(),
        function( $className ) use ( $interfaceName ) {
            return in_array( $interfaceName, class_implements( $className ) );
        }
    );
}

【讨论】:

【解决方案4】:

要检查谁实现了特定接口,您可以编写如下函数:

<?php
/**
 * Get classes which implement a given interface 
 * @param string $interface_name Name of the interface
 * @return array Array of names of classes. Empty array means input is a valid interface which no class is implementing. NULL means input is not even a valid interface name.
 */
function whoImplements($interface_name) {
    if (interface_exists($interface_name)) {
        return array_filter(get_declared_classes(), create_function('$className', "return in_array(\"$interface_name\", class_implements(\"\$className\"));"));
    }
    else {
        return null;
    }
}

示例调用var_export(whoImplements('ArrayAccess')); 的输出如下:

[sandbox]$ php whoimplementswhat.php
Array
(
    [29] => CachingIterator
    [30] => RecursiveCachingIterator
    [38] => ArrayObject
    [39] => ArrayIterator
    [40] => RecursiveArrayIterator
    [48] => SplDoublyLinkedList
    [49] => SplQueue
    [50] => SplStack
    [55] => SplFixedArray
    [56] => SplObjectStorage
    [111] => Phar
    [112] => PharData
)

这样,您无需使用循环,并且可以在较低版本的 PHP 上运行您的代码。函数array_filter 在内部循环,但在 PHP 执行引擎内部(因此比用 PHP 代码编写的循环性能更高)。

【讨论】:

  • 这样就不用循环了,可以在低版本的PHP上运行代码。
  • 你知道为什么我看到一个空数组,尽管我确实在实现接口吗?
  • @Netbulae 一定有问题。将您的代码放入键盘并分享链接。
  • 啊,没关系。提示:类没有被声明。我使用的是一厢情愿的设计模式:p
  • array_filter 仍然在内部循环整个数组,所以“不要使用循环”语句是不正确的。
猜你喜欢
  • 2014-08-25
  • 2011-10-21
  • 2015-08-27
  • 2013-12-16
  • 2014-01-13
  • 1970-01-01
  • 2016-05-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多