1

我有一个包含作者和书籍的数据库,m:n authors (a_id, ...) authors_books (a_id, b_id) books (b_id, ...)

我的问题是,我不能使用构造函数将作者/书籍数据获取到数组中,因为我会得到一个无限循环。

class Book
{

    public $name;
    public $authors;

    public function __construct($name)
    {
        $this->name=$name;
        $this->authors=$this->Get_Authors();
    }

    public function Get_Authors()
    {
        $authors=array();
        /* ... (database) */
        $authors[]=new Author($name_from_db);
        return $authors;
    }

}

class Author
{

    public $name;
    public $books;

    public function __construct($name)
    {
        $this->name=$name;
        $this->books=$this->Get_Books();
    }

    public function Get_Books()
    {
        $books=array();
        /* ... (database) */
        $books[]=new Book($name_from_db);
        return $books;
    }

}

例子:

new Book('book_1');

-> 将获取 'author_1' 并使用 Author 类的 __constructor

new Author('author_1');

-> 将获取 'book_1 并使用 Book 类的 __constructor ...

解决 PHP 类中 am:n 关系的“最佳实践”是什么?

4

2 回答 2

2

您可以在此处使用延迟加载:

class Book {

    public $name;
    private $_authors = null;

    public function __constructor($name) {
        $this->name = $name;
    }

    public function getAuthors() {
        if ($this->_authors === null) {
            $this->_authors = array();
            /* database */
            $this->_authors[] = new Author(/**/);
        }
        return $this->_authors;
    }

    // You can add some magic getter if you want to access authors as property
    public function __get($key) {
        if ($key === 'authors') {
            return $this->getAuthors();
        }
        throw new Exception('Unknown property '.$key);
    }
}

class Authors {

    public $name;
    private $_books = null;

    public function __constructor($name) {
        $this->name = $name;
    }

    public function getBooks() {
        if ($this->_books === null) {
            $this->_books = array();
            /* database */
            $this->_books[] = new Book(/**/);
        }
        return $this->_books;
    }

    // You can add some magic getter if you want to access books as property
    public function __get($key) {
        if ($key === 'books') {
            return $this->getBooks();
        }
        throw new Exception('Unknown property '.$key);
    }
}

这将导致作者/书籍仅在您需要时才会加载并且不会无限循环,但您可以在此处遇到另一个问题:

$author = new Author("Jon Doe");
$book = $author->books[0];
// assuming that book has one author
// $book->authors[0] will not be same object as $author

解决方案是使用第三个对象来加载书籍和作者,它将存储已加载的对象并将它们注入适当的位置

class Library {

    private $_books = array();
    private $_authors = array();

    public function getBooksForAuthor($authorId) {
        /* db query... */
        $books = array();
        while ($row = $stmt->fetch()) {
            if (isset($this->_books[$row['id']]) {
                $books[] = $this->_books[$row['id']];
            } else {
                $book = new Book($row);
                $this->_books[$row['id']] = $book;
                $books[] = $book;
            }
        }
        return $books;
    }

    /* and similar authorsForBook() method */
}

class Author {

    private $_data;
    private $_library;
    private $_books = null;

    public function __constructor($data, $library) {
        $this->_data = $data;
        $this->_library = $library;
    }

    public function getBooks() {
        if ($this->_books === null) {
            $this->_books = $this->_library->getBooksForAuthor($this->_data['id']);
        }
        return $this->_books;
    }

    public function __get($key) {
        if ($key === 'books') {
            return $this->getBooks();
        }
        if (isset($this->_data[$key]) {
            return $this->_data[$key];
        }
        throw new Exception('Unknown property '.$key);
    }
}

/* and similar for book */
于 2013-01-18T10:36:31.677 回答
0

为什么要加载所有相关对象?使用“延迟加载”——在需要之前不要加载所有相关对象。在您的情况下,这意味着通过他们的 getter 方法获取相关对象。如果您需要通过属性获取它们,您可以通过魔术方法实现 getter。

于 2013-01-18T10:35:35.743 回答