在php中获取父类的所有已定义类

30

我需要在所有文件都被包含(include)之后确定哪些类继承(extend)了一个父类,所以:

class foo{
}
class boo extends foo{
}
class bar extends foo{
}

我希望能够获取类似这样的数组:

array('boo','bar');

http://stackoverflow.com/questions/538863/getting-the-name-of-a-child-class-in-php - Darragh Enright
不太对,那需要运行构造函数,我正在寻找已声明但未必被运行的类。 - Trey
1
可能是 Get all extended Classes in PHP 的重复问题。 - jeremy
1
除了那些在2年前被问过的…… - Trey
这取决于您在获取实现接口/扩展类的所有类之后想要做什么。 - Ahmad Hajjar
4个回答

31

参考Wrikken的回答,结合Scott BonAmi的建议进行修正,得到如下结果:

$children = array();
foreach( get_declared_classes() as $class ){
  if( is_subclass_of( $class, 'foo' ) )
    $children[] = $class;
}

is_a()instanceof的其他建议都不适用于此,因为它们都期望一个对象实例,而不是一个类名。


27

如果你需要这样做,那么它看起来像糟糕的代码,基类不应该知道这个。

不过,如果你已经包含了定义(即你不需要包含可能有的新类文件),你可以运行:

$children  = array();
foreach(get_declared_classes() as $class){
    if($class instanceof foo) $children[] = $class;
}

3
除了我正在使用is_a而不是instanceof之外,这基本上就是我的代码...我知道你为什么会这样想,但基类实际上不需要知道任何事情,这更像是一个插件管理器函数 :) - Trey
5
它有点老旧,但您可以使用is_subclass_of (链接)代替is_ainstanceof - sbonami
4
谢谢@ScottBonAmi,你的回答起作用了,但是is_a()instanceof对我来说不起作用,因为这两个都期望一个对象,而不是一个类名。 - MikeSchinkel
1
通常情况下,这应该会失败,因为现代应用程序将使用自动加载,在这种情况下类没有被定义。get_declared_classes()将返回一个未定义的应用程序状态列表,因为有些类已经被加载而其他类没有。 - Matthias Kleine
3
我希望指出的是,这并不像是“糟糕代码”所散发的味道——它更接近于动态类反射。这就是为什么会存在反射函数以及为什么动态类创建/加载有很多好处。 - phillihp
显示剩余6条评论

7

使用

$allClasses = get_declared_classes();

获取所有类的列表。

然后,使用PHP反射功能来构建继承树。


我知道这已经过时了,但感谢您指向反射类,它们缺乏大多数php.net的完整文档,但在一些不同的地方非常有用。+1 - Trey

3
我很确定以下解决方案或类似的解决方案将适用于您的问题。在我看来,您可以使用以下方法(这有点像观察者模式):
1. 定义一个名为Fooable的接口。
interface Fooable{
    public function doSomething();
}

2- 所有的目标类必须实现该接口:

class Fooer implements Fooable{
    public function doSomething(){
         return "doing something";
    }
}

class SpecialFooer implements Fooable{
    public function doSomething(){
         return "doing something special";
    }
}

3- 创建一个注册类,将其称为FooRegisterar

class FooRegisterar{
    public static $listOfFooers =array();

    public static function register($name, Fooable $fooer){
         self::$listOfFooers[$name]=$fooer;
    }
    public static function getRegisterdFooers(){
         return self::$listOfFooers;
    }
}

4- 在您的启动脚本或被包含在启动脚本中的某个脚本中:

FooRegisterar::register("Fooer",new Fooer());
FooRegisterar::register("Special Fooer",new SpecialFooer());

5- 在你的主代码中:

class FooClient{

    public function fooSomething(){
         $fooers = FooRegisterar::getRegisterdFooers();
         foreach($fooers as $fooer){
              $fooer->doSomthing();
         }
    }
}

1
让我用另一种方式来问你这个问题,你为什么需要它?我的意思是,为什么你需要在不预先知道它们的情况下获取所有继承某个类的类? - Ahmad Hajjar
1
你将你的问题标记为OOP,这就是为什么我发布这个答案的原因,因为这就是一个OOP解决方案的样子 :) - Ahmad Hajjar
3
不管原因是什么,在5年前我问这个问题时,我正在构建一个插件自动加载器。我知道可能会有几百个插件,但某些页面只有十几个插件,所以接受的答案允许我缓存结果,无需知道所有类或实例化它们。 - Trey
1
不确定我可以用多少种不同的方式来表达这个问题。插件系统本身是面向对象的,我正在寻找一种动态的方法来查找和注册这些插件,而不需要实例化它们,你的“解决方案”可能是在页面加载时实现插件注册的一种方式,但并没有解决动态发现插件的需求。如果你不知道它们的存在,那么“Fooer”和“Special Fooer”从哪里来? - Trey
1
没有人紧张,你没有回答我的问题,你提供的解决方案在需求不同的情况下是完全可以接受的。 - Trey
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接