Search code examples
phpclassdomdocumentautoloadspl-autoload-register

php spl_autoload_register() doesn't load a class


I have an index.php that require Test1 class trough spl_autoload_register(). In the Test1 class the Test2 class is required with the same autoload but this error occurred:

Fatal error: DOMDocument::registerNodeClass(): Class Test2 does not exist in...

I tried to see if the autoload work writing $test2 = new Test2(); and it works well. So with other tests I realized that with registerNodeClass() the autoload doesn't include the Test2 class file.

Is there anyone who can help me?

Test1.php

<?php

namespace Test;

use Test\Test2;

class Test1
{
    function __construct($html)
    {
        $this->dom = new \DOMDocument();
        @$this->dom->loadHTML($html);
        $this->dom->registerNodeClass('DOMElement', 'Test2');
    }
}

?>

Test2.php

<?php

namespace Test;

class Test2 extends \DOMElement
{

//bla, bla, bla...

}

?>

index.php

<?php

require_once('./autoload.php');

use Test\Test1;

$html = 'something';

$test = new Test1($html);

?>

autoload.php (it is the same used by Facebook for the php-sdk)

<?php
/**
 * An example of a project-specific implementation.
 * 
 * After registering this autoload function with SPL, the following line
 * would cause the function to attempt to load the \Foo\Bar\Baz\Qux class
 * from /path/to/project/src/Baz/Qux.php:
 * 
 *      new \Foo\Bar\Baz\Qux;
 *      
 * @param string $class The fully-qualified class name.
 * @return void
 */
spl_autoload_register(function ($class) {

    // project-specific namespace prefix
    $prefix = 'Test\\';

    // base directory for the namespace prefix
    $base_dir = __DIR__ . '/src/';

    // does the class use the namespace prefix?
    $len = strlen($prefix);
    if (strncmp($prefix, $class, $len) !== 0) {
        // no, move to the next registered autoloader
        return;
    }

    // get the relative class name
    $relative_class = substr($class, $len);

    // replace the namespace prefix with the base directory, replace namespace
    // separators with directory separators in the relative class name, append
    // with .php
    $file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';

    // if the file exists, require it
    if (file_exists($file)) {
        require $file;
    }
});
?>

Solution

  • class Test2 is within namespace Test, so in order to do new Test2() you must be within the namespace Test or you can specify the fully qualified name (ie new Test\Test2()) to instantiate the class.

    When you call $this->dom->registerNodeClass('DOMElement', 'Test2');, DOMDocument does something to the affect of:

    $extendedClass = 'Test2';
    $obj = new $extendedClass();
    

    And it doesn't find Test2 because that code isn't called from the Test namespace. So you would need to pass the fully qualified class name (w/ namespace).

    Use: $this->dom->registerNodeClass('DOMElement', 'Test\Test2');