2

I'm trying to trick PHP into taking a class from another namespace when trying to create a specific class.

I have two class called "page", the first is in the Core namespace:

namespace Core;
class Page {...}

The second inherits from Core\Page, but adds a few things. It is in the Addons namespace.

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

The reason I want to do this is because I want to build my system with an easy addon engine. Whenever I want, I can add a line in an XML file that tells the autoloading function to take the class in the addon namespace instead of the core namespace.

However, when I try to do this :

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

I get an error saying that the class \Core\Page cannot be found in the file Addons\Page.php. This is normal behaviour since the class is not in the same namespace and as such, the fully qualified name cannot find the right class.

Is it possible to trick PHP into thinking that a child class in another namespace is actually the right class? I tried this for the addons class;

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

But it breaks the inheritance as you cannot inherit yourself.

1
  • The problem is you have to include both classes to make the Addons\Page work. There is no way around it. Commented Jul 8, 2016 at 14:59

1 Answer 1

2

Ignore that the classes have the "same name". Because they don't. One class is called Core\Page, the other is called Addons\Page. Those are their names, their fully qualified names to be exact. It's as much a difference as Foo and Bar. If you tell PHP to instantiate Core\Page, then it's going to do that; you can't "trick" it into instantiating Addons\Page, since that's an entirely different class name.

Don't try to "trick" anyone, make your system actually extensible and explicitly allow overriding of class names:

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

$page = new $class;
Sign up to request clarification or add additional context in comments.

5 Comments

The things is, I want my system to be unaware of the addon's existence, this is why I use the Autoloader. For example, If I create a page object in the route class, I don't, want my route class to have 10 if for all possible addons over page.
It's simply not possible. You could replace a class outright by creating another Core\Page class in your addon and load that instead. But then it's impossible to extend the existing Core\Page class, because you'd have to load it in order to extend it, but if you do that you can't replace it anymore (Class already defined error). It's also a terrible idea from a maintenance standpoint to slyly exchange implementations "behind PHP's back", it's just going to lead to a lot of headaches. Make your system explicitly extensible.
Okay thanks, your confirmed what I feared. Would it be a good idea to build an object factory that builds all objects for the core and is tasked with checking if an addon exists? It seems a bit counter intuitive to have to write objectfactory::create("Core\Page"); instead of new Core\page(); Do you have a better idea?
In the end that's what you have to do. You want to be able to do it both ways: instantiate Core\Page if you explicitly want to, but also conditionally instantiate some overridden class. I can't stress this enough: you want to be explicit about which is going to happen. new Core\Page should always instantiate Core\Page. $dependencyContainer->getPageInstance() should conditionally get the current applicable class. You're only going to shoot yourself in the foot sooner or later if new Core\Page would instantiate something other than Core\Page.
I'll do that, thanks. It'll break the intelicence, but that's to be expected with PHP anyway.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.