5

I've defined an abstract superclass in one file and a subclass in another. I have required the super-classes file and the stack trace reports to find an include it.

However, it then returns an error when it hits the 'extends' line: Fatal error: Class 'HTMLBuilder' not found in View/Markup/HTML/HTML4.01/HTML4_01Builder.php on line 7.

I had this working with another class tree that uses factories a moment ago. I just added the builder layer in between the factories and the consumer. The factory layer looked almost exactly the same in terms of includes and dependencies.

So that makes me think I must have done something silly that's causes the HTMLBuilder.php file to not be included correctly or interpreted correctly or some such.

Here's the full stack trace (paths slightly altered):

#   Time    Memory  Function    Location
1   0.0001  53904   {main}( )   ../index.php:0
2   0.0002  67600   require_once( 'View/Page.php' ) ../index.php:3
3   0.0003  75444   require_once( 'View/Sections/SectionFactory.php' )  ../Page.php:4
4   0.0003  81152   require_once( 'View/Sections/HTML/HTMLSectionFactory.php' ) ../SectionFactory.php:3
5   0.0004  92108   require_once( 'View/Sections/HTML/HTMLTitlebarSection.php' )    ../HTMLSectionFactory.php:5
6   0.0005  99716   require_once( 'View/Markup/HTML/HTMLBuilder.php' )  ../HTMLTitlebarSection.php:3
7   0.0005  103580  require_once( 'View/Markup/MarkupBuilder.php' ) ../HTMLBuilder.php:3
8   0.0006  124120  require_once( 'View/Markup/HTML/HTML4.01/HTML4_01Builder.php' ) ../MarkupBuilder.php:3

Here's the code in question:

Parent class (View/Markup/HTML/HTMLBuilder.php):

<?php

require_once('View/Markup/MarkupBuilder.php');

abstract class HTMLBuilder extends MarkupBuilder {

    public abstract function getLink($text, $href);

    public abstract function getImage($src, $alt);

    public abstract function getDivision($id, array $classes=NULL, array $children=NULL);

    public abstract function getParagraph($text, array $classes=NULL, $id=NULL);

}

?>

Child Class, (View/Markup/HTML/HTML4.01/HTML4_01Builder.php):

<?php

require_once('HTML4_01Factory.php');
require_once('View/Markup/HTML/HTMLBuilder.php');


class HTML4_01Builder extends HTMLBuilder {
    private $factory;

    public function __construct() {
        $this->factory = new HTML4_01Factory(); 
    }

    public function getLink($href, $text) {
        $link = $this->factory->getA();
        $link->addAttribute('href', $href);
        $link->addChild($this->factory->getText($text));
        return $link;   
    }

    public function getImage($src, $alt) {
        $image = $this->factory->getImg();
        $image->addAttribute('src', $src);
        $image->addAttribute('alt', $alt);
        return $image;
    }

    public function getDivision($id, array $classes=NULL, array $children=NULL) {
        $div = $this->factory->getDiv();
        $div->setID($id);
        if(!empty($classes)) {
            $div->addClasses($classes);
        }   
        if(!empty($children)) {
            $div->addChildren($children);   
        }
        return $div;
    }

    public function getParagraph($text, array $classes=NULL, $id=NULL) {
        $p = $this->factory->getP();
        $p->addChild($this->factory->getText($text));
        if(!empty($classes)) {
            $p->addClasses($classes);   
        }
        if(!empty($id)) {
            $p->setID($id); 
        }
        return $p;
    }

}


?>
2
  • What's the value of include_path? Commented Apr 24, 2010 at 22:42
  • include_path => .:/usr/share/php:/usr/share/pear => .:/usr/share/php:/usr/share/pear Commented Apr 24, 2010 at 22:48

1 Answer 1

2

Note that, in the trace, HTMLBuilder.php requires MarkupBuilder.php requires HTML4_01Builder.php. You've got an include cycle. When HTML4_01Builder is defined, PHP hasn't finished processing HTMLBuilder.php. In particular, it hasn't reached the beginning of the abstract class HTMLBuilder definition.

There's no need to include a descendent class when defining the ancestor. PHP uses late binding of class names, so the descendent only needs to exist by the time the methods are invoked.

MarkupBuilder.php:

<?php
// unnecessary: 
//require_once('View/Markup/HTML/HTML4.01/HTML4_01Builder.php');

class MarkupBuilder {
    static public function getInstance(...) {
        ...
        return new HTML4_01Builder(...);
Sign up to request clarification or add additional context in comments.

4 Comments

Yeah, I noticed that. The strange thing is the Factory tree has the exact same include cycle. Identical in structure. It worked with out a hiccup.
@Daniel: do you mean there's an abstract factory class defined in a file that directly or indirectly includes a file that defines a descendent of the abstract factory class before the base class is defined? I bet it's not exactly the same as that.
Exactly the same. MarkupFactory has a get instance function that returns an instance to HTML4_01Factory(). HTML4_01Factory is a descends from HTMLFactory which in turn descends from MarkupFactory. Same loop - it worked. When I was writing that code it did tick off a warning flag, but I decided to go ahead and try it anyway.
Son of a gun... I had the exact same dependency loop working fine elsewhere in the program, and a very similar one in another spot. However, removing all the dependency loops was all it took to fix the problem. boggles Code works in mysterious ways. I won't question. My code is prettier now - aside from having a FactoryAndBuilderFactory ;)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.