为每个父母的班级孩子实例化一个实例?

Posted

技术标签:

【中文标题】为每个父母的班级孩子实例化一个实例?【英文标题】:Instantiating one instance each of parent's class children? 【发布时间】:2017-08-02 02:46:23 【问题描述】:

为了测试我的东西,我想为我命名的父类的每个子类自动实例化一个实例,而无需手动调用类名(太多了)。

例如:

Class Animal 
  public weight;


Class Dog extends Animal 
  public weight = 20;


Class SmallDog extends Dog 
  public weight = 18;


Class Cat extends Animal 
  public weight = 10;



function xy()
  $classes = array();
  foreach parent->child as child()
    $classes[] = new child()
  
  //$classes = [Dog, SmallDog, Cat]

像 (tm) 这样的东西是否可行,如果可行,如何实现?

作为进一步的信息,我有一个包含每个类的 autoload_register,但它也包含我不想实例化的各种类。 另外,相对于上面的例子,我将 Animal、Dog 和 Cat 都组装在一个文件中,我们称之为 animal.php

在上面的代码中,我会得到一个低于 Animal 的任何实例,包括 SmallDog。如果不可能,我可以得到 Dog 和 Cat 并调用父为 Dog 的函数(以实例化 SmallDog)。

感谢您的建议,

【问题讨论】:

您可以使用get_declared_classes()ReflectionClass::getParentClass() 来查找扩展某个类的类(假设所有包含子类的文件都已加载)但这会使您的代码更难阅读和理解.只列出子类要清楚得多。您可以使用一些简单的 shell 脚本(grepsed/cut 等)从代码中提取子类列表。 这违背了测试的想法。您可以继承和覆盖函数,因为每个子类的行为与其父类不同。您必须对它们进行测试。 【参考方案1】:

这在实际情况下并不是很有用,但使用@axiac 注释可以实现ChildrenResolver 类:

class ChildrenResolver
 
    protected $defaultClasses = [
        0 => 'stdClass',
        1 => 'Exception',
        2 => 'ErrorException',
        // ...
    ];

    protected $declaredClasses;

    public function __construct(array $declaredClasses = null)
    
        if (is_null($declaredClasses)) 
            $declaredClasses = array_diff(
                get_declared_classes(),
                $this->defaultClasses
            );
        

        $this->declaredClasses = $declaredClasses;
    

    public function getChildClasses($class)
    
        return array_filter(
            $this->declaredClasses,
            function ($declaredClassName) use ($class) 
                $declaredClass = new ReflectionClass($declaredClassName);

                while(($parent = $declaredClass->getParentClass())) 
                    if ($parent->name === $class) 
                        return true;
                    

                    $declaredClass = $parent;
                

                return false;
            
        );
    

    public function getDirectChildClasses($class)
    
        return array_filter(
            $this->declaredClasses,
            function ($declaredClassName) use ($class) 
                $declaredClass = new ReflectionClass($declaredClassName);

                $parent = $declaredClass->getParentClass();

                return $parent ? $parent->name === $class : false;
            
        );
    

这个想法很简单。我们循环声明的类(通过get_declared_classes 获得),使用ReflectionClass 反映每个类,并将我们从ReflectionClass::getParentClass 获得的父类与给定的父类进行比较。为了方便起见,我使用了array_filter 函数。

有了这个类,你可以像这样解决孩子:

$childrenResolver = new ChildrenResolver;

var_dump($childrenResolver->getChildClasses('Animal'));
var_dump($childrenResolver->getDirectChildClasses('Animal'));
var_dump($childrenResolver->getChildClasses('Dog'));

这里是working demo。

【讨论】:

以上是关于为每个父母的班级孩子实例化一个实例?的主要内容,如果未能解决你的问题,请参考以下文章

如何在运行时控制实例化的预制件作为孩子

为什么不能实例化我的班级,但是我可以在另一个项目中呢?

在实例化之前设置属性默认值

是否为每个操作实例化了 ActionFilterAttribute?

为每个 TableViewCell 实例化新数组

EaselJS:从库中实例化对象后如何访问子项