【问题标题】:Override object creation with same class in another namespace在另一个命名空间中使用相同的类覆盖对象创建
【发布时间】:2016-11-11 04:04:43
【问题描述】:

当我试图创建一个特定的类时,我试图欺骗 PHP 从另一个命名空间中获取一个类。

我有两个名为“page”的类,第一个在 Core 命名空间中:

namespace Core;
class Page {...}

第二个继承自 Core\Page,但增加了一些东西。它位于 Addons 命名空间中。

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

我想这样做的原因是因为我想用一个简单的插件引擎来构建我的系统。每当我需要时,我都可以在 XML 文件中添加一行,告诉自动加载函数将类放在插件命名空间而不是核心命名空间中。

但是,当我尝试这样做时:

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

我收到一条错误消息,指出在 Addons\Page.php 文件中找不到类 \Core\Page。这是正常行为,因为该类不在同一个命名空间中,因此,完全限定名称无法找到正确的类。

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

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

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

【问题讨论】:

  • 问题是你必须包含 both 类才能使Addons\Page 工作。没有办法解决它。

标签: php namespaces autoload


【解决方案1】:

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

不要试图“欺骗”任何人,让您的系统真正可扩展并明确允许覆盖类名:

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

$page = new $class;

【讨论】:

  • 问题是,我希望我的系统不知道插件的存在,这就是我使用自动加载器的原因。例如,如果我在路由类中创建一个页面对象,我不希望我的路由类有 10 个 if 对于页面上所有可能的插件。
  • 这根本不可能。您可以通过在插件中创建另一个 Core\Page 类并加载它来直接替换一个类。但是extend 现有的Core\Page 类是不可能的,因为你必须加载它才能extend 它,但如果你这样做,你就不能再替换它了(Class already defined 错误)。从维护的角度来看,“在 PHP 背后”狡猾地交换实现也是一个糟糕的想法,它只会导致很多麻烦。 使您的系统显式可扩展。
  • 好的,谢谢,你证实了我的担心。构建一个为核心构建所有对象并负责检查插件是否存在的对象工厂是一个好主意吗?必须编写 objectfactory::create("Core\Page"); 似乎有点违反直觉。而不是 new Core\page();你有更好的主意吗?
  • 最后这就是你必须做的。您希望能够以两种方式做到这一点:如果您明确想要实例化Core\Page,但也有条件地实例化一些被覆盖的类。这一点我怎么强调都不为过:您想明确说明会发生什么。 new Core\Page 应该始终实例化 Core\Page$dependencyContainer-&gt;getPageInstance() 应该有条件地获取当前适用的类。如果new Core\Page 会实例化Core\Page 以外的其他东西,你迟早只会在脚下开枪。
  • 我会这样做的,谢谢。它会破坏智能,但无论如何这都是 PHP 所期望的。
猜你喜欢
  • 2012-03-14
  • 2012-09-12
  • 2017-12-13
  • 1970-01-01
  • 1970-01-01
  • 2016-09-16
  • 1970-01-01
  • 2010-10-14
  • 2013-11-14
相关资源
最近更新 更多