在现有代码库中,我有一个返回实例的静态构建器方法。这是一个简化的例子:
class Grandparent{
}
class Parent extends Grandparent{
}
class Child extends Parent{
public static fetchChildById($id){
// ...
return new Child;
}
}
在实际代码中,我有一个Grandparent
类和几个类似于Parent
和Child
的子类(不只是Parent
和Child
)。
我现在需要在Grandparent
实施一个新方法,以便在fetchChildById()
使用。这种方法需要利用同一父母的所有孩子共有的某些数据。由于我没有类实例,但我不得不将所有内容都设置为静态,但当然,由于无法覆盖静态属性和方法,因此无法正常工作:
class Grandparent{
protected static $data = array(
'default',
);
protected static function filter(){
foreach(self::$data as $i){ // <!-- Will always be `default'
// ...
}
}
}
class Parent extends Grandparent{
protected static $data = array(
'one',
'two',
);
}
class Child extends Parent{
public static fetchChildById($id){
self::filter();
// ...
return new Child;
}
}
我认为这是后期静态绑定的一个用例,但代码需要在PHP / 5.2.0上运行:(
我不太喜欢我曾经想过的明显的解决方法:
创建一个单独的构建器类建议在此时进行更多的重构:
$builder = new ChildBuilder;
$bart = $builder->fetchChildById(1);
创建其他实例看起来很丑陋(也暗示了许多更改):
$builder = new Child;
$bart = $builder->fetchChildById(1);
全局变量......哦,我还没那么绝望。
我是否忽略了一些明确的机制来自定义$data
?
答案 0 :(得分:1)
这是使用反射的另一种选择。它需要修改所有fetchChildById
实现,但它足以完成全局查找/替换:
self::filter(__CLASS__); // this is the modification
然后filter
将成为:
protected static function filter($className){
$reflect = new ReflectionClass($className);
$data = $reflect->getStaticPropertyValue('data');
foreach($data as $i){
// ...
}
}
更新:属性$data
需要公开才能使上述工作正常工作(道歉 - 我在探索期间写了public
)。但是,这是一个没有这个要求的同等版本:
$reflect = new ReflectionProperty($className, 'data');
$reflect->setAccessible(true);
$data = $reflect->getValue();