I’ve created two very basic Interfaces named ReaderInterface and WriterInterface, but I have removed WriterInterface from this example since it is unnecessary to illustrate my conundrum.
ReaderInterface.php
interface ReaderInterface
{
public function read();
}
I have a concrete class called Datatable:
Datatable.php
class Datatable
{
protected $cols;
protected $rows;
protected $reader;
public function __construct()
{
$this->cols = array();
$this->rows = array();
$this->reader = null;
}
public function setReader(ReaderInterface $reader)
{
$this->reader = $reader;
}
public function load()
{
//Contents to follow below.
}
}
I instantiate a datatable instance as follows:
$db = new PDO("mysql:host=localhost;port=3306;dbname=test", "user", "pass"); //Let's pretend this is a good connection.
$datatable = new Datatable();
$datatable->setReader(new DatatableReader($db));
$datatable->load();
My question is about implementing DatatableReader so that it can read from the database I pass in, and write to $this->cols and $this->rows in my Datatable object.
I see two approaches right off.
1. Dependency Injection
class DatatableReader implements ReaderInterface
{
protected $db;
protected $datatable;
public function __construct(Datatable &$datatable, PDO &$db)
{
$this->datatable = $datatable;
$this->db = $db;
}
public function read()
{
//Execute prepared statement which returns 5 records.
//Get the columns, and place them into an array.
foreach ($columns as $col) {
$this->datatable->addColumn($col); //Add a column to the datatable.
}
}
}
Then, my Datatable::load() method would be implemented as:
public function load()
{
if ($this->reader != null)
$this->reader->read();
}
2. Weakly typed return from read().
class DatatableReader implements ReaderInterface
{
protected $db;
public function __construct(PDO &$db)
{
$this->db = $db;
}
public function read()
{
//Execute prepared statement which returns 5 records.
//Get the columns, and place them into an array.
return $columns;
}
}
I would then call my load() method as follows:
public function load()
{
if ($this->reader != null) {
$retval = $this->reader->read();
//Do stuff with the array of information returned from the reader.
}
}
Questions
- Of these two options, which is the best design?
- Is there a third option that I’m overlooking?
I would go with option 2. With option 1 you produce a recursion:
DatatableReadercontains objectDatatableand vice versa.The other bad thing with option 1 is that you abuse the
readmethod to write to another object.And only the concrete implementation (
DatatableReader) knows about that object.All objects that implements an interface should react in the same way.