I'm learning about OOD and good practices in OOP and find myself struggling with some key concepts. As a practice I'm rewriting my custom PDO database abstraction layer which used to be a single file class with >2000 lines of code.
I learned one should use inheritance if classes are in a "is an" relationship and composition if they have a "has a" relationship. Composition can be implemented as this, given that I would avoid php's traits
(example from here):
<?php
class Head {
}
class Human {
private $head;
public function __construct(Head $head) {
$this->head = $head;
}
}
$bob = new Human(new Head);
Good. However, in my case I want to composite a class B to A, while there can be multiple instances of B. Precisely, the main database
class (A) has one or multiple table
classes (B). Injecting a table
object similar to the head
object in the above example might be not what I want. Later, there might be also maybe a select class or a insert class. I do this just for practice and learn how I can keep my classes small in file size. Should I all inject all dependencies during construction and recylcle them? Or should I instantiate them within the main database
class and inject the connection to the subclasses. The main database class holds the PDO object in '$_connection'.
Q1: what is the best way to compose the classes database
and table
.
I can think of these strategies.
Strategy #1
<?php
class db extends PDO{
private $_connection;
public function __construct($dsn){
$this->_connection = new parent::__construct($dsn);
}
public function createTable($def){
$table = new Table(this->_connection, $def);
}
}
Cons:
- I have the
new
operator in a method which I assume is generally not ideal. Better, I should inject all instances. - I have to declare a
createTable
method in the base class. This spams my base class. If functionality increases the base class will be bigger and bigger, which is what I wanted to circumvent in the first place. I would rather like to be able to callcreate
on the table object as inTable->create()
. - I'm not sure about the the injection of the connection to the table class. Is that good practice?
Strategy #2
<?php
class db extends PDO{
private $_connection;
public $table;
public function __construct($dsn, $table){
$this->_connection = new parent::__construct($dsn);
$this->table = $table;
}
}
$db = new db($dsn, new $Table)
$db->table->create($def);
Cons:
- I don't have the
connection
available in the Table class as it is neither a child nor is the connection manually injected.
I don't think the db and Table classes are in a "is a" relationship and thus should not be inherited from each other. But currently I'm lacking a good composition implementation.
Disclaimer
I tried to work for a solution but need help on what could be the best practice for this. Composition, as posted with the example (human, head), just doesn't feel right here in the case of database and table. I hope I'll receive helpful answers, also links or buzz words are welcome as I'm just learning and I seem to have a hard time to enter the next level.