views:

200

answers:

5

I am trying to take advantage of autoloading in PHP. I have various classes in different directories, and so I have bootstrapped the autoloading as follows:

function autoload_services($class_name)
{
    $file = 'services/' . $class_name. '.php';
    if (file_exists($file))
    {
        require_once($file);
    }
}

function autoload_vos($class_name)
{
    $file = 'vos/' . $class_name. '.php';
    if (file_exists($file))
    {
        require_once($file);
    }
}

function autoload_printers($class_name)
{
    $file = 'printers' . $class_name. '.php';
    if (file_exists($file))
    {
        require_once($file);
    }
}

spl_autoload_register('autoload_services');
spl_autoload_register('autoload_vos');
spl_autoload_register('autoload_printers');

It all seems to work fine, but I just wanted to double check that this is indeed considered acceptable practise.

A: 

It's okay, but if these are just folders below a certain folder, e.g.

/library
    /JonoB
        /services
        /vos
        /printers

you might want to consider adding these to your classnames, e.g.

JonoB_Services_Foo, JonoB_Vos_Bar, JonoB_Printers_Baz

and then split the $classname by the underscore and take each part as folder name. This is similar to PEAR class name convention. This way you would only have one loader.

Instead of PEAR convention style classnames, you can also use namespaces (autoload example), but be aware that these require PHP5.3 which is not widely available on shared hosting yet. And your application won't be backwards compatible with PHP<5.3 then (if that's an issue).

Gordon
This is fine if you're stuck with PHP <5.3 and expect to be for a long time, but as indicated by GameBit, you're much better off using namespaces instead of polluting your names like this. (Moving away from such name pollution is one of the big goals for Zend Framework 2.)
mr. w
@mr.w ZF2 will use namespaces, but as far as I know, [ZF2.0 will stick to the PEAR/PSR-0 conventions in terms of file layout and eventually introduce class mapping in addition](http://weierophinney.net/matthew/archives/245-Autoloading-Benchmarks.html), so the only difference is parsing the namespace instead of the classname.
Gordon
@mr.w besides, the PEAR convention is common practise and I'd hardly call it namespace pollution. It's what ZF does now, too. I'd agree to the library should have have unique prefix to avoid clashes with other libraries and added that.
Gordon
Not namespace pollution - *name* pollution. And certainly, naming a class JonoB_Services_Foo is pollution of the name and messy compared to simply Foo. This is what ZF 1.x does because there weren't really any better alternatives when it was created, but with ZF 2, they're dropping that convention in favor of namespaces, which will shorten class names considerably. For brief discussion, see http://framework.zend.com/wiki/display/ZFDEV2/Zend+Framework+2.0+Requirements#ZendFramework2.0Requirements-MakeCodeReadable
mr. w
@mr.w yes, of course it will shorten classnames, but what does that have to do with autoloading? The folder hierarchy will stay the same. Like I said, the only difference will be whether you are parsing the namespace or the classname. Instead of `Zend_Registry`, you will have `Zend\Registry` and that still will be in `library/Zend/Registry.php`. In addition, shorter names all good, but with 5.3 not being widely available on shared hosting and lots of people simply not seeing any advantage in using namespaces anyway, I dont know why complain about the current best practise?
Gordon
I was commenting on the suggestion to represent the directory hierarchy within the class names, not on the directory hierarchy itself. I think the latter is just fine, but the former is a bad idea if running under 5.3. Heavily prefixed names are common because, prior to 5.3, there was no better way to solve the very real problem of namespace clashes. With 5.3, namespaces offer a much more elegant solution that has impact beyond how classnames are parsed for auto-loading. As for shared hosting, that's a separate issue that, sadly, has long plagued PHP.
mr. w
@mr.w Sorry, but no. Prefixed classnames are not a *bad idea* all of a sudden just because there is namespaces now. They do solve the namespace clashing issue and they are backwards compatible. Overly long classnames aint exactly pretty but how often does that really matter? In ZF it can become an issue when you exceed the max line length. That's it. I find having to type long classnames not any more annoying than having to use the ugly backslash or having to import or lookup namespaces up front. I agree namespaces are a good addition, but they sure aint elegant or mandatory.
Gordon
A: 

... or just use namespaces ...

GameBit
+1  A: 

Sure, looks good. The only thing you might do is register them in the order they're most likely to hit. For example, if your most commonly used classes are in services, then vos, then printers, the order you have is perfect. This is because they're queued and called in-order, so you'll achieve slightly better performance by doing this.

mr. w
A: 

Good advice from all the other answers.

Let me add that each autoloader should first check if it even cares about the class being passed in, and return immediately if not.

So if you do as Gordon suggests and add a prefix to each class, then for Services_Foo the autoloader autoload_services() should see if "Services_" is the first substring of $class_name, and if not return false immediately to save on any further processing, especially filesystem checks.

Fanis
A: 

You could use:

set_include_path(get_include_path() . PATH_SEPARATOR . './services' . PATH_SEPARATOR . './vos' . PATH_SEPARATOR . './printers');
spl_autoload_register();

Using spl_autoload_register without arguments will register spl_autoload which will look for the class name in the directories of the include path. Note that this will lowercase the class name before looking for it on the filesystem.

nikic