3

I am developing a web framework in PHP, and I want to make it fully extendable. My goal is to make it possible for a developer to change the behavior of any component without having to modify the "core" codebase at all. Developers should be able to encapsulate all of their work in a separate directory. And, I want to do this without using "hooks" (i.e., event listeners), which can quickly turn into a huge mess.

For most components, I have this figured out:

  • The Pimple DI container allows you to extend existing services.
  • I'm using Twig as my template engine, which allows templates to be overridden.
  • Front controller routes can be overridden by redefining them.
  • I'm using an extendable uniform resource locator to allow developers to override or add search paths for resources (assets, configuration, schema, etc).

The problem I face is extending the functionality of a class when there are places in the core codebase that already instantiate that class (because my framework is a full-fledged application rather than a library, even with IoC, I still need to instantiate the class at some point).

Inheritance alone won't solve this problem, because I'm still instantiating the base class in my core controllers/routes/whatever. It would seem that I need to introduce an additional layer of abstraction.

One idea I have is to just use PHP's dynamic class instantiation feature. For example, if I have a base User class, and I want to allow developers to replace all instances with a CustomUser class:

// In a config file (which *can* be overridden) 
$userClassName = "User";

...

// Anywhere I need a User, or User subclass: 
$user = new $userClassName(...);

Now, a dev simply needs to override the value of $userClassName and set it to the name of their child class.

Alternatively, I could wrap this all in a Factory pattern:

class UserFactory
{
    public function createUser($type = "User", $args)
    {
        return new $type($args);
    }
}

The advantage of the Factory class would be that I could do some type-checking, but then I'd need a separate Factory for each base class.

Are either of these approaches the right way to implement this kind of extensibility?

  • And, I want to do this without using "hooks" (i.e., event listeners), which can quickly turn into a huge mess. Why do you think that? – Andy Aug 12 '16 at 20:46
  • @david-packer Because, you have to predict every single point in the code where a developer might want to inject functionality. In the extreme, you could end up with code where every other line in the code is an event emitter! – alexw Aug 12 '16 at 21:21
  • Framework is a tool to solve common problems so they do not need to be solved over and over again and which are required by pretty much any project (routing, autoloading,...). If you feel like every other lc could be an event emitter you're getting at it from the wrong side. Your framework is usually not supposed to do everything. It's just supposed to make things easier. Most projects contain a completely framework-agnostic core anyway where the business logic lives, that's usually the main part of an application. Framework is just a handy wrapper. – Andy Aug 12 '16 at 21:36
  • @DavidPacker it is more like a "framework+". This write-up might explain better what I am trying to create. – alexw Aug 12 '16 at 22:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.