2

Can anyone tell me if it's possible to override a use statement?

My example is having an MVC setup where there is core code with the ability to override each Controller / Model with a custom version that extends the core version.

The issue I face is that my core controller has a use statement telling it to use the core model, so if I extend the model, I'm not sure how to tell it to use the custom model rather than the core one

I could obviously update the core controller use statement to point to the custom one, but the core code is shared so the custom version may not exist on other sites that use this core core

Use statements are obviously file level so I'm guessing it's not possible, but I'm hoping there's either something I don't know about or maybe a workaround

Example

Core controller

namespace Core;

use Core\Model\Example as ExampleModel;

class ExampleController {

    public function output() {
        $model = new ExampleModel;
        $model->test();
    }

}

Core Model

namespace Core;

class ExampleModel() {

    public function test() {
        echo 'This is the core test';
    }

}

Custom Controller

namespace Custom;

use Custom\Controller\Example as Base,
    Custom\Model\Example as ExampleModel;

class ExampleController extends Base {

    //Inherits the output() method

}

Custom Model

namespace Custom;

use Core\Model\Example as Base;

class ExampleModel extends Base {

    public function test() {
        echo 'This is the custom test';
    }

}

So given this example, is it possible for me to create an instance of the custom controller which uses the custom model to output 'This is the custom test', without modifying the core code at all?

Hopefully what I'm asking makes sense

Thanks

kinger198
  • 577
  • 1
  • 5
  • 15
  • 1
    `use` is just a trivial detail here. Your controller extends a certain class, period. You can't change that without changing your controller's source code. – deceze Jul 08 '14 at 11:16
  • Also your namespaces have **nothing to do with the filesystem**. That's a thing to keep in mind. Your way to go would be to override the `output()` method and instantiate the object there (if you absolutely need to). – thpl Jul 08 '14 at 11:20

1 Answers1

2

I'm not quite sure I understand your question, but the answer should be self-evident: If your custom model extends from the core model, you can simply extend another class from that custom class
If you are writing code, that depends on a child of the core class being present, then that child class becomes a vital part of your project. If you can't change the core itself, add that class as a dependency. It's as simple as that.

Adding a second layer of inheritance needn't worry you, it's perfectly common to do so. Something like this is perfectly predictable, and reliable:

namespace Core;
class Model
{
    public function coreTest()
    {
        return 'from the core';
    }
}
namespace Custom;
use Core\Model;
class CustomModel extends Model
{
    public function customTest()
    {
        return 'from the custom model';
    }
}
//finally
namespace Project;
use Custom\CustomModel;
class ProjectModel extends CustomModel
{
    public function test()
    {
        return array(
            $this->coreTest(),
            $this->customTest(),
            'From the project'
        );
    }
}
$test = new ProjectModel();
echo implode(PHP_EOL, $test->test());

If, however you want a given class to extend from another class, based on whether or not that class exists, you are looking for conditional imports.
A simple use statement is evaluated at compile-time, so there's no way you can use an if check to switch between which class you extend from.

There is, however a hacky work-around, but I wouldn't rely on it. Check if the given class exists (without autoloading), and set an alias to the class that does.

if (!class_exists('\\Custom\\Model', false))
    class_alias('\\Core\\Model', 'Base');
else
    class_alias('\\Custom\\Model', 'Base');
class CustomModel extends Base
{}

But really: don't go down this route. Sure your code will work, but if you then rely on a method being available, that was defined in the custom class, but that class was missing, then your code will fail... horribly.

Details on conditional imports:

Why use class alisases?

Community
  • 1
  • 1
Elias Van Ootegem
  • 74,482
  • 9
  • 111
  • 149
  • Thank you for the answer. Conditional imports would definitely solve my issue but I'll try and avoid using them if possible. I think my best option know I know there isn't a non hacky way to do conditional use statements will be to always have custom, blank versions of the core classes or to override any method that uses the custom model. Thanks again – kinger198 Jul 08 '14 at 13:16