1

私は著者と本を含むデータベースを持っています.m:n著者(a_id、...)著者_本(a_id、b_id)本(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

その解決策は、本と著者をロードするために何らかの第 3 のオブジェクトを使用することです。このオブジェクトは、既にロードされているオブジェクトを保存し、適切な場所に挿入します。

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

関連するすべてのオブジェクトをロードする必要があるのはなぜですか? 「遅延読み込み」を使用します。関連するすべてのオブジェクトは、必要になるまで読み込まないでください。あなたの場合、ゲッターメソッドを介して関連オブジェクトを取得することを意味します。プロパティを介して取得する必要がある場合は、魔法のメソッドを介してゲッターを実装できます。

于 2013-01-18T10:35:35.743 に答える