1

Second update

I think I've been approaching this problem from the wrong side of the coin. Would I be correct in assuming that I should be making 'First' an abstract class and just finding a way to reference 'Second' and 'Third' at a later time?

Update

Based on some of the feedback, I have added some content to try and clear up what I would like to do. Something similar to this effect.

I know from just looking at the code below that, it is a waste of performance "if" it did work and because it doesn't, know I am approaching the problem from the wrong angle.The end objective isn't all to uncommon at a guess from some of the frameworks I've used.

I'm more trying to base this particular bit of code on the CodeIgniter approach where you can define (what below) is STR_CLASS_NAME in a config file and then at any point through the operation of the program, use it as i have dictated.

STR_CLASS_NAME = 'Second';

class First {
    protected $intTestOne = 100;

    public function __construct() {
         $strClassName = STR_CLASS_NAME;
         return new $strClassName();
    }

    public function TestOne() {
        echo $this->intTestOne;
    }

    protected function TestThreePart() {
        return '*Drum ';
    }
}

class Second extends First{
    /* Override value to know it's working */
    protected $intTestOne = 200;

    /* Overriding construct to avoid infinite loop */
    public function __construct() {}

    public function TestTwo() {
        echo 'Using method from extended class';
    }

    public function TestThree() {
        echo $this->TestThreePart().'roll*';
    }
}

$Test = new First();
$Test->TestOne(); <-- Should echo 200.
$Test->TestTwo(); <-- Should echo 'Using method from extended class'
$Test->TestThree(); <-- Should echo '*Drum roll*'

You may be asking, why do this and not just instantiate Second, well, there are cases when it is slightly different:

STR_CLASS_NAME = 'Third';

class Third extends First{
    /* Override value to know it's working */
    protected $intTestOne = 300;

    /* Overriding construct to avoid infinite loop */
    public function __construct() {}

    public function TestTwo() {
        echo 'Using method from extended class';
    }

    public function TestThree() {
        echo $this->TestThreePart().'snare*';
    }
}

$Test = new First();
$Test->TestOne(); <-- Should echo 300.
$Test->TestTwo(); <-- Should echo 'Using method from extended class'
$Test->TestThree(); <-- Should echo '*Drum snare*'

Situation

I have a an abstract class which extends a base class with the actually implementation; in this case a basic DB wrapper.

class DBConnector ()
class DBConnectorMySQLi extends DBConnector()

As you can see, MySQLi is the implementation. Now, dependant upon a value in the configuration process, a constant becomes the class name I wish to use which in this case (as shown below builds DBConnectorMySQLi.

define('STR_DB_INTERFACE', 'MySQLi');
define('DB_CLASS', 'DBConnector'.STR_DB_INTERFACE);

Objective

  • To have a base class that can be extended to include the implementation
  • For the code itself not to need know what the name of the implementation actually is
  • To (in this case) be able to type or use a project accepted common variable to create DBConnectorMySQLi. I.E. $db or something similar. W

Issue

When it comes to actually calling this class, I would like the code to be shown as below. I was wondering whether this is at all possible without the need to add any extra syntax. On a side note, this constant is 100% guaranteed to be defined.

$DBI = new DB_CLASS();

Solution 1

I know it is possible to use a reflection class ( as discussed in THIS QUESTION) and this works via:

$DBI = new ReflectionClass(DB_CLASS);

However, this creates code that is "dirtier" than intended

Solution 2

Start the specific implementation of DBConnectorMySQLi within the constructor function of DBConnector.

define('STR_DB_INTERFACE', 'MySQLi');
define('DB_CLASS', 'DBConnector'.STR_DB_INTERFACE);

class DBConnector() { public function __construct() { $this->objInterface = new DBConnectorMySQLi(); }
class DBConnectorMySQLi()

This however would result in the need to keep on "pushing" variables from one to the other

Any advice is much appreciate

Community
  • 1
  • 1
Simon
  • 816
  • 2
  • 7
  • 16
  • What I have ended up doing (rather than trying to twist something that doesn't want to be twisted) is to make (according to the example given) 'First' an abstract class and just have the others extend it. Now, the whole point of this exercise was so that when it comes to operation, make it easy to write code once for different interfaces so have a basic service controller E.G. Target multiple databases or render content for different transmission methods all using the same 'content base'. DRY principles and Dependency injection still prevail. – Simon Nov 29 '13 at 10:20

1 Answers1

0

You can use variables when you instantiate a class.

$classname = DB_CLASS;
$DBI = new $classname();

Source: instantiate a class from a variable in PHP?

Community
  • 1
  • 1
Jared
  • 2,978
  • 4
  • 26
  • 45
  • That method (of which I use elsewhere) requires the extra line of code. It has made me think of another message I will try though – Simon Nov 29 '13 at 06:55
  • Try `$DBI = new ($classname = DB_CLASS)()`. It probably won't work though. Why do you need it on one line? – Jared Nov 29 '13 at 07:03
  • 1
    I have an existing project that requires some refactoring and am just pondering exactly what options are available. As mentioned in the title, this is me thinking about ways I can pull it off whilst creating the tidiest possible code – Simon Nov 29 '13 at 08:11
  • 4
    I'm all for tidy code, but sometimes you just need to add that extra line. It's sometimes good for clarity, too. – Jared Nov 29 '13 at 09:07
  • 3
    Tidiest !== smallest. If it takes two lines to express something in a clear and understandable way, then you should do that. – shanethehat Nov 29 '13 at 09:12
  • Thanks for the feedback, I will definitely take that in to account and understand; sometimes it is easy to get carried away! I have update my question to wholly give example of what I mean, is there any way to achieve that? – Simon Nov 29 '13 at 09:31