Search code examples
phpoopchaining

How to retrieve ancestor while chaining instances of classes


I'm developping an application in PHP in which the ( jQuery-like) style of chaining methods is extremely convienent. I'm not talking about inheritance chains, but about a taxonomy of instances of classes that are 'embedded' inside each other. Now I wonder how I can refer to a higher level instance from a lower level.

This sounds all very abstract, so let me give an example. Let's say I want to write a book (proze) in PHP (just for the sake of arguement). It's very conveniently if I could code this like

$myBestseller = new Book();

$myBestseller
  ->setAuthor("Jean-Saul Partre")
   ->addChapter()
    ->addParagraph("How the Rabit lost its wings.")
        ->addWords("On a beautiful wintes day, the rabit flew over the … ") 
        ->addWords("Bla bla") 
        ->addWords("Bla bla");

So far, I got it working. (Should I include the actual class definions?) Now what if I would like to refer to a property of an object higher in the hierarchy? Let's say I'd like to include the name of the author in a the title of a chapter:

    $myBestseller = new Book();

    $myBestseller
      ->setAuthor("Jean-Saul Partre")
       ->addChapter()
        ->addParagrapWithAuthor("How "," fell out of the window.");
            ->addWords("Bla bla")
            ->addWords("Bla bla")
            ->addWords("Bla bla")

    var_dump($myBestseller);

Let's just add the Chapter class definition here as well:

class Chapter{
  private $_paragraphs = array();

  public function addParagraph($title){
    return $this->_pages[] = new Paragraph($title);
  }

  public function addParagrapWithAuthor($prefix, $suffix){
    $author = "Ideo Gram";
    return $this->_pages[] = new Paragraph($prefix.$author.$suffix);
  }
}

So, instead of $author = "Ideo Gram" I'd want to use the definition of the author of the book. The title with this code would be

How Ideo Gram fell out of the window

Instead, I would like it to say

How Jean-Saul Patre fell out of the window

Can this be done? The only solution so far I found is passing a reference to descendents 'under the table', but that feels like contaminating the classes.

Maybe the answer is very straight forward, but I can't find it. I might not know the right terms. ::parent, for example, works on extended classes.


Solution

  • There is no magic. If you need a bidirectionnal relationship between 2 entities, they need to reference each other.

    So your method addChapter could do this :

    public function addChapter() {
        return $this->chapters[] = new Chapter($this);
    }
    

    So your chapter becomes :

    class Chapter {
    
        protected $book;
    
        public function __construct(Book $book) {
            $this->book = $book;
        }
    
        ....
    
        public function addParagrapWithAuthor($prefix, $suffix){
            $author = $this->book->getAuthor()->getFullName();
            return $this->_pages[] = new Paragraph($prefix.$author.$suffix);
        }
    }