PHP Autoloading in Namespaces
Asked Answered
S

3

11

I have had a slight problem with autoloading in my namespace. As shown on the PHP manual here: http://us.php.net/manual/en/language.namespaces.rules.php you should be able to autoload namespace functions with a full qualified name e.g. \glue\common\is_email().

Thing is I have a function spl_autoload_register(array($import, "load")); within the initial namespace but whenever I try and call \glue\common\is_email() from the initial namespace it will not pass that autoload function but when using new is_email() (in the context of a class) it will. I don't get it the manual says I can autoload from fully qualified names but I can't :.

Here's my code:

namespace glue;

require_once 'import.php';

use glue\import as import;
use glue\core\router as router;

$import = new import();

spl_autoload_register(array($import, "load"));

/** Works and echos glue\router **/
$router = new router();

/** Don't do nothing **/
$cheese = \glue\common\is_email($email);

I also tried this code as well:

namespace glue;

require_once 'import.php';

use glue\import as import;
use glue\core\router as router;
use glue\common;

$import = new import();

spl_autoload_register(array($import, "load"));

/** Works and echos glue\router **/
$router = new router();

/** Don't do nothing **/
$cheese = common\is_email($email);

and finally this code:

namespace glue;

require_once 'import.php';

use glue\import as import;
use glue\core\router as router;
use glue\common\is_email as F;

$import = new import();

spl_autoload_register(array($import, "load"));

/** Works and echos glue\router **/
$router = new router();

/** Don't do nothing **/
$cheese = F($email);
Swill answered 4/9, 2010 at 12:31 Comment(1)
Retagged as php5.3 as this is a 5.3-only question.Henrieta
H
16

Here's the only right answer.

Every namespace needs its own spl_autoload_register() function.

also, spl_autoload_register() syntax changed in 5.3:

spl_autoload_register(__NAMESPACE__ . "\\className::functionName"));

The following should work:

namespace glue;

require_once 'import.php';

use glue\import as import;
use glue\core\router as router;

$import = new import();

spl_autoload_register(__NAMESPACE__ . "\\$import::load"));

/** Works and echos glue\router **/
$router = new router();

/** Don't do nothing **/
$cheese = \glue\common\is_email($email);

Here is some live code that Just works!

in ../WebPageConsolidator.inc.php:

class WebPageConsolidator
{
    public function __construct() { echo "PHP 5.2 constructor.\n"; }
}

in test.php:

<?php

namespace WebPage;

class MyAutoloader
{
    public static function load($className)
    {
        require '../' . __NAMESPACE__ . $className . '.inc.php';
    }
}

spl_autoload_register(__NAMESPACE__ . "\\MyAutoloader::load");

class Consolidator extends \WebpageConsolidator
{
    public function __construct()
    {
        echo "PHP 5.3 constructor.\n";

        parent::__construct();
    }
}

// Output: 
// PHP 5.3 constructor.
// PHP 5.2 constructor.

So I know it works.

Henrieta answered 4/9, 2010 at 13:16 Comment(3)
Seemed like it could work but it still won't load my function. I'm starting to think PHP still overrides this functionality with it's runtime binding...which would kinda suck.Swill
Yea it only goes into spl_autoload when using the new keyword........grrr why does PHP manual say I can autoload functions if I can't, might have to take this to them.Swill
Yea as I still thought, dammit being able to load functions dependant on resolution of namespace to directory structure would be well good. I might suggest it to them, thanks for your help :).Swill
F
1

The misconception in the question of the OP is probably that functions/methods would be subject to autoloading – which they are not. Autoloading is only triggered by referencing classes.

This being said there still remains the question about autoloading classes in namespaces:

As of 2017 the current PHP-FIG standard for autoloading is PSR-4 which provides the following autoloader code for namespaced classes:

<?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 = 'Foo\\Bar\\';

    // 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;
    }
});

The full spec text can be found at PSR-4: Autoloader.

The code example above (and another one to autoload from multiple namespaces) can be found at Example Implementations of PSR-4 (or GitHub: fig-standards/accepted/PSR-4-autoloader-examples.md).

Finesse answered 11/5, 2017 at 14:29 Comment(3)
Actually now PHP7 does allow autoloading of functions and methods in namespaces directlySwill
Hi @Sammaye, thanks for the hint. Do you have some link with more information at hand? I can't seem to find anything about that change.Finesse
I don't know where @Swill got that from. Tried in 7.2.28 and does not work. Autoloading gets triggered by classes only. I already knew that, and it is in the PHP docs, but evidence beats ipse dixit =)Thornhill
M
0

Use Composer to autoload your PHP Classes.

Check out how to do it in my recent blog post: https://enchanterio.github.io/enterprise-level-php/2017/12/25/the-magic-behind-autoloading-php-files-using-composer.html

Mattland answered 26/12, 2017 at 15:49 Comment(4)
The reason why this would work now is because php now allows autoloading of namespace functionsSwill
Sure. 7 years later many things have changed haha. I wanted to put here a reference to the new way of doing it as I landed in this question myself from Google.Mattland
Link enterprise-level-php.com/2017/12/25/… is brokenStatement
@Statement thx for letting me know. I suspended the website few weeks ago, I just deployed to github pages at least so you can check out the article, link in the answer updated.Mattland

© 2022 - 2024 — McMap. All rights reserved.