gbuckingham89
gbuckingham89

Reputation: 385

Overriding PHP Class Instantiation

I'm currently working on a project where we are developing an application that will be used to power content on multiple sites from a single set of files / hosting environment.

There are a number of PHP classes with names such as model_account and model_vehicle which are defined in seperate files named the save as the class name. We are using spl_autoload_register to load the class files as below (simplified):

function my_autoloader($class_name) {
    if(substr($class_name, 0, 6)=='model_') {
        require_once('models/'.$class_name.'.php');
    }
}

What we want to do, is if the visitor is accessing site xxx and we create an instance of a class, eg $account = new model_account(); - actually create an instance of class model_xxx_account if the file exists (models/model_xxx_account.php), but if it doesn't, just include the models/model_account.php file and create an instance of model_account.

Likewise, if a visitor came from site yyy, we would want to use model_yyy_account if exists, but full back to model_account if it doesn't.

Essentially what we wish to do is create an instance of a different class if conditions are met, but from the same instantiation call.

We're not using an off-the-shelf framework like CI or Cake. Also, I've slightly simplified the naming conventions for this post. Sorry if my OO terminology isn't spot on.

Upvotes: 1

Views: 490

Answers (4)

Anther
Anther

Reputation: 1844

It actually sounds like you should be using some sort of factory pattern to deal with your class loading.

If you do $account = new SomeClass(), it does not make any sense to ever really end up with an object of class Bumblebee.

You should technically have some sort of account factory that decides which class to give you.

You code will end up looking more like $account = AccountFactory::retrieveModel(), which then can determine which model you want to load WITHOUT delegating to your autoloader.

The point of the autoloader is to essentially say "I want THIS exact class", and isn't to be wibbly wobbly or in particular be making any sort of decisions of that sort. Your factory can actually go through your file structure and determine which class to pass back in the function call, and in your code you aren't relying on new to get the model you want, since it seems in theory all of your account models will be sharing the same interface or at least extending model_account.

AccountFactory can essentially say, "model_yyy_account exists, thus return new model().

Upvotes: 5

CodeAngry
CodeAngry

Reputation: 12985

$SiteID = 'xxx'; // Modify as you wish from your subdomain or whatever
// class_exists triggers the autoloader
if(!class_exists($ClassName =  "model_{$SiteID}_account")){
    // If class is missing, fall back to default
    $ClassName =  "model_account"; // This should exist
}
$Model = new $ClassName(); // Instantiate your Account Model

Just make sure $SiteID contains _ and alphanumerics hence is class name friendly.

And never do require_once from relative paths. Alway do:

require_once __DIR__.'/models/'.$class_name.'.php'; // PHP 5.3+
// or
require_once dirname(__FILE__).'/models/'.$class_name.'.php'; // PHP 5.2-

to stay safe. This way you know exactly where you are seeking the Account Model class.

Upvotes: 1

Devraj
Devraj

Reputation: 3065

You can certain do this:

$className = "MyClassName";
$myObject = new $className();

Where you can dynamically define $className based on what your conditions are.

Upvotes: -1

GolezTrol
GolezTrol

Reputation: 116100

I think you can't. The autoloader only helps you selecting a file to include, not allowing you to change the class.

But that shouldn't be a problem. You can just name the classes for each website model_account. The site determines which file gets included and thus which version of model_account is instantiated. Because you will never (assumption) need both model_xxx_account and model_yyy_account in a single request, they won't interfere which each other, even if they have the same name.

PS: I would name the files the same as well, and create a separate folder for each site and a folder with defaults. That will make it easier to spot overriden files per site and shrinks the risk of name clashes.

Upvotes: 2

Related Questions