Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP OOP design structure [closed]

Tags:

oop

php

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();
  1. First of all, is this a good OOP approch?

  2. 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?

  3. 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?

like image 462
Andy Avatar asked Nov 13 '22 22:11

Andy


1 Answers

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.

like image 141
JvdBerg Avatar answered Nov 15 '22 11:11

JvdBerg