我正在将我开发的一系列类转换为使用名称空间。
其中一个类有一个依赖项:
namespace VENDOR
class A{
static public function(){
B::getInfo();
}
}
文件B namespace VENDOR;
class B{
static public function getInfo(){
//some work
}
}
然后,这属于我将包含到项目中的个人库。B
类易扩展:
namespace APPNAMESPACE
class SuperB extends 'VENDOR'B{
static public function getInfo(){
//Some different work
}
}
我的意图是VENDOR'A调用APPNAMESPACE'SuperB,但在这里我看到我没有设计好我的系统,因为显然它将继续调用VENDOR' b。
在此之前,我可以实现这种行为,因为我根本没有使用名称空间,而是使用经典的类命名约定DIR_CLASS.php,它允许我的自动加载器(现在使用composer)首先在高优先级的APP文件夹中查找,如果没有在其他优先级较低的文件夹中找到(类似于kohana, Codeigniter等)。
那么我如何处理这个(显然没有硬编码APPNAMESPACE'SuperB到VENDOR'A)
如果没有状态,这很快就会变得棘手。这个有是静态调用的原因吗?如果可能的话,我倾向于使用(可配置的、可测试的、可交换的、可测试的)实例。
这样做要容易得多:
namespace VENDOR
class A{
protected $b;
public function __construct(B $b){
$this->b = $b;
}
public function something(){
$this->b->getInfo();
}
}
…所以你可以加入你喜欢的东西。可能,构造函数中的B类型提示更应该是一个接口,而不是一个类定义,并且您可能无法控制外部供应商为您提供的内容。
如果我们假设你不能碰VENDOR的代码,我认为没有合理的工作方法。如果它需要是静态的(并且需要长时间思考为什么会这样),并且可以触摸代码,这样做可能会起作用,但我不喜欢它,因为它更难检查,调试和强制类名的一致性(OTOH,未经测试):
namespace VENDOR
class A{
protected static $b = 'B';
static public function something(){
call_user_func(array(self::$b,'getInfo'));
}
static function useB($classname){
if(!in_array(''VENDOR'B',class_implements($classname))){
trigger_error("$classname does not implement 'VENDOR'B", E_USER_ERROR);
}
self::$b =
}
}
再次选择一个接口而不是一个实现来检查。但是,如果您想进一步扩展'VENDOR'A,我们可能会再次遇到static::/self::问题。这是"一种"的功能,你看到@ $PDO->setAttribute(PDO::ATTR_STATEMENT_CLASS, 'A class that extends PDOStatement');
的例子,但你已经立即看到,它被调用在一个实例(和事实,它需要扩展而不是实现PDOStatement
有更多的c级实现/该类的功能)。