My questions applies to these three example classes I have made up for getting a better understanding of how to use OOP.
class Book {
//not using getters/setters to save some space
public $name;
public $numreads;
}
class BookFactory {
private $db;
public function __construct(Database $db) {
$this->db = $db;
}
public function getBook($id) {
$book = new Book();
$book->name = $db->query("SELECT name FROM books...");
$booknumreads = new BookNumRead($this->db, $book);
$book->numreads = $booknumreads->getFromLocal() + $booknumreads->getFromAnotherSource();
return $book;
}
}
class BookNumRead {
private $db;
private $book;
public function __construct(Database $db, Book $book) {
$this->db = $db;
$this->book = $book;
}
public function getFromLocal()
{
return $this->db->query("SELECT COUNT ... WHERE name = $book->name");
}
public function getFromAnotherSource()
{
return API::getNumReadsOfABook($book->name);
}
//or just stick with this method in this class
public function getNumReadsOfBook($name)
{
return (
$this->db->query("SELECT COUNT ... WHERE name = $name")
+
API::getNumReadsOfABook($name)
);
}
}
//get number of reads of a book
$db = new Database();
$bookfactory = new BookFactory($db);
$book = $bookfactory->getBook(123);
echo $book->getNumReads();
First of all, is this a good OOP approch?
These classes is quite different. Domain vs Value objects? For example, there can be as many Book objects as I need in my application. The BookFactory however is like a service in my application, there only needs to be one in my application but I may need this class from many other places in my application, should i put it as a object in a ServiceLocator/ServiceContainer?
The BookNumRead class could also be put in a ServiceLocator/ServiceContainer, and be used by the getNumReadsOfBook() method without a Book object injected, but that feels like procedural programming? Or, as in the example above be iniated by the BookFactory::getBook(), but then I need to pass both a Database (that one BookFactory got injected) and a Book to it, and that feels a little bit messy, beacasue it may need other "service" classes like a logger for example. What is best practice here?
I think you should separate the DB stuff more from your Models/Services. Use a adapter pattern for the DB stuff and handle all SQL in a separate class. You could make the adapter implementing PDO, MySQLi etc.
Think at a higher, more pragmatic level of your models and services, and hide the implementation details in underlying, universal classes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With