1

Regarding my post here: problems when extending a PHP Class

What's the best solution? And why?


$query = $this->Execute("SELECT * FROM $table");
$total = $this->NumRows($query);

Or


$query = DBManager::Execute("SELECT * FROM $table");
$total = DBManager::NumRows($query);

Or


$query = parent::Execute("SELECT * FROM $table");
$total = parent::NumRows($query);

Community
  • 1
  • 1
Cheerio
  • 1,260
  • 6
  • 19
  • 37
  • if you override the execute function you need to use $this, if not i think the other options are the best way, I don't know if exists any differences between [parentClassName] or parent, but i will choose the second one – raultm Jan 29 '11 at 11:07

4 Answers4

2

When you extend a class, the child class can call all the public and protected methods and properties of the parent class in addition to any the child defines. If you do not need to override the parent's methods, but just want to use them somewhere inside the child, use

public function somethingUsingExecute()
{    
    $query = $this->Execute("SELECT * FROM $table");
    …
}

If you need to override execute in a child class but also want to call that method with the original functionality of the parent, use

public function execute($table)
{
    // can do something not in parent before parent call
    $query = parent::Execute("SELECT * FROM $table");
    // can do something not in parent after parent call
}

The static call

$query = DBManager::Execute("SELECT * FROM $table");

is something you should forget it exists, because you are hardcoding a classname into the using class and also couple the method call to the global scope. Both is hard to test and maintain. I won't go into more details, because this has been discussed on SO before. Just give it a search.


The "best trick" regarding that User/DBManager example would actually be not use inheritance at all. Inheritance creates an is-a relationship. The child is a special case of the parent. But a User is not a DBManager (I'd call it DbAdapter btw).

The responsibility of your DBManager class is to allow access to the database. Your User does not have that responsibility. It uses the DBManager to get access to the database, but it does need to know how to do that in detail. The DBManager already does.

Any class using another class should be injected/aggregated. So, what you should do is:

class User …

    protected $db;
    protected $isAuthenticated = FALSE;

    public function __construct($db)
    {
        $this->db = $db;
    }

    public function authenticate($username, $password)
    {
        if($this->db->query('SELECT … ')) {
            $this->isAuthenticated = TRUE;
        }
        return $this->isAuthenticated;
    }

    …
}

Then you can do

$db = new DBManager;
$john = new User($db);
$john->authenticate('JohnDoe', 'jd/12345');
$jane = new User($db);
$jane->authenticate('JaneDoe', 'jd/67890');
$logger = new DBLogger($db);
$logger->log('something to db');

Injecting the DB class has the added benefit that you can reuse the existing DBManager instance in other using classes. If you extend the DBManager class, each new instance will create a new connection to the database, which is undesired for performance reasons.

Gordon
  • 312,688
  • 75
  • 539
  • 559
0

There is a difference between statically calling the functions (option 2 and 3) and calling them as non-static functions. It depends on your whole set-up

Nanne
  • 64,065
  • 16
  • 119
  • 163
0
  • $this points to the current instance of the class.
  • DBManager points to the parent class, but of course, if you change its name, you have to change your code.
  • parent points to the class from which this one inherits, no matter its name.

So, in this example I don't think it matters much, without further details on how you would use your classes and instances. But, if for example you plan to have multiple instances of the DB class, you probably should use $this, at least if you want to store the queries or results without overwrite them with your next query (as raultm suggested).

AJJ
  • 7,365
  • 7
  • 31
  • 34
0

I would go with the second option if we are limited to your options (otherwise read item 3 below), because:

1) when you write

$query = $this->Execute("SELECT * FROM $table");
$total = $this->NumRows($query);

it seams like you have one class, which executes queries (all kind of), and processes result of some specific queries (in your case number of rows. Imagine you have two entities, both of them are stored in tables (different), you will have two classes and both of them will either duplicate Execute method logic, or one entities DAO will use another to execute its Execute method (but these entities can be and mostly will be not related, so you will harm OOP principles)

2) now your last case

$query = parent::Execute("SELECT * FROM $table");
$total = parent::NumRows($query);

better than previous one, but in this case you DAOs are inherited from a class, which performs query execution... I'm not sure that it is right way to go, Imagine you have two different storages, like database and xml, to retrive information from first one you will use SQL, for last one it will be probably XPath; to work with storage you will use the same interface and two implementations, not the question - which one to inherit for your User class? No one, they are not related; User entity should not have any idea where is it stored.

3) Last case

$query = DBManager::Execute("SELECT * FROM $table");
$total = DBManager::NumRows($query);

it sound like delegating (sorry, I'm not that familiar with PHP), here you specify which class to use to process queries, for me, when I read this code, it sounds like Execute/NumRows are static methods of DBManager class (again sorry, I just use my architecture knowledge to help you and basic conventions for e.g. Java to read your code). In this case I would recommend you to create instance of DBManager and then use it:

class UserDAO {  
   private $storageManager = new DBManager();

   ...  
   $query = $storageManager::Execute("SELECT * FROM $table");  
   $total = $storageManager::NumRows($query);  
   ....  
}

something like this (please correct me if I made mistake in PHP code; for now just look at it like 'the way to go', abstract algorithm description ;). In this case, if have to switch to another implementation of DBManager, you will just change line private $storageManager = new DBManager(); and that's all.

Maxym
  • 11,836
  • 3
  • 44
  • 48