2016-07-08 20 views
0

我试图让PHP在尝试创建特定类时从另一个命名空间获取一个类。用另一个命名空间中的同一类替代对象创建

我有两个班被称为“页”,首先是在核心命名空间:

namespace Core; 
class Page {...} 

从核心\页第二继承,但增加了一些东西。它位于Addons名称空间中。

namespace Addons; 
class Page extends \Core\Page{...} 

我想这样做的原因是因为我想用简单的插件引擎构建我的系统。无论何时,我都可以在XML文件中添加一行,告诉自动加载功能在addon命名空间而不是核心命名空间中使用该类。

然而,当我尝试这样做:

spl_autoload_register('loadClass'); 

public function loadClass(string $className) 
{ 
    if (Addon_exist_and_is_registered($className)) 
    { 
     require "/Addons/$className.php"; 
    } 
    else 
    { 
     require "/Core/$className.php"; 
    } 
} 

$page = new \Core\Page(); <-- error here 

我得到一个错误,说\核心\页面无法在文件扩展中心中发现的类\ page.php文件。这是正常的行为,因为该类不在同一个名称空间中,因此,完全限定的名称找不到正确的类。

是否有可能让PHP认为另一个命名空间中的子类实际上是正确的类?我为插件类尝试了这个;

namespace Core; 
class Page extends \Core\Page{...} 

但它打破了继承,因为你不能继承自己。

+0

的问题是,你必须包含** **双方班,使' Addons \ Page'工作。没有其他办法了。 – apokryfos

回答

2

忽略这些类具有“相同名称”。因为他们没有。一类叫做Core\Page,另一类叫​​。 这些是他们的名字,他们的完全合格的名称是确切的。这与FooBar有很大不同。如果你告诉PHP实例Core\Page,那么它会这样做;你不能“欺骗”它来实例化​​,因为这是一个完全不同的类名。

不要试图“欺骗”的人,让你的系统实际上可扩展的和明确允许类名的压倒一切的:

$class = 'Core\Page'; 
if (...) { 
    $class = 'Addons\Page'; 
} 

$page = new $class; 
+0

事情是,我希望我的系统不知道插件的存在,这就是我使用Autoloader的原因。例如,如果我在路由类中创建一个页面对象,我不希望我的路由类有10个,如果对于页面上的所有可能的插件。 – GPierre

+0

这根本不可能。你可以通过在你的插件中创建另一个Core \ Page类来直接替换一个类并加载它。但是现在''扩展'现有的'Core \ Page'类是不可能的,因为你必须加载它才能“扩展”它,但是如果你这样做了,你就不能替换它了('Class already defined '错误)。从维护的角度来看,狡猾地交换“背后的PHP”背后的实现也是一个可怕的想法,这只会导致很多令人头痛的问题。 **使您的系统明确可扩展。** – deceze

+0

好的,谢谢,您证实了我所担心的。建立一个为核心构建所有对象并负责检查插件是否存在的对象工厂会是一个好主意吗?这似乎有点反直觉必须编写objectfactory :: create(“Core \ Page”);而不是新的Core \ page();你有更好的主意吗? – GPierre

相关问题