views:

104

answers:

4

PHP's __autoload() (documentation) is pretty interesting to me. Here's how it works:

  • You try to use a class, like new Toast_Mitten()(footnote1)
  • The class hasn't been loaded into memory. PHP pulls back its fist to sock you with an error.
  • It pauses. "Wait," it says. "There's an __autoload() function defined." It runs it.
  • In that function, you have somehow mapped the string Toast_Mitten to classes/toast_mitten.php and told it to require that file. It does.
  • Now the class is in memory and your program keeps running.

Memory benefit: you only load the classes you need. Terseness benefit: you can stop including so many files everywhere and just include your autoloader.

Things get particularly interesting if

1) Your __autoload() has an automatic way of determining the file path and name from the class name. For instance, maybe all your classes are in classes/ and Toast_Mitten will be in classes/toast_mitten.php. Or maybe you name classes like Animal_Mammal_Weasel, which will be in classes/animal/mammal/animal_mammal_weasel.php.

2) You use a factory method to get instances of your class.

$Mitten = Mitten::factory('toast');

The Mitten::factory method can say to itself, "let's see, do I have a subclass called Toast_Mitten()? If so, I'll return that; if not, I'll just return a generic instance of myself - a standard mitten. Oh, look! __autoload() tells me there is a special class for toast. OK, here's an instance!"

Therefore, you can start out using a generic mitten throughout your code, and when the day comes that you need special behavior for toast, you just create that class and bam! - your code is using it.

My question is twofold:

  • (Fact) Do other languages have similar constructs? I see that Ruby has an autoload, but it seems that you have to specify in a given script which classes you expect to use it on.
  • (Opinion) Is this too magical? If your favorite language doesn't do this, do you think, "hey nifty, we should have that" or "man I'm glad Language X isn't that sloppy?"

1 My apologies to non-native English speakers. This is a small joke. There is no such thing as a "toast mitten," as far as I know. If there were, it would be a mitten for picking up hot toast. Perhaps you have toast mittens in your own country?

+1  A: 

I think this feature comes in very handy, and I have not seen any features like it else where. Nor have I needed these features else where.

Petah
A: 

Java has something similar. It's called a ClassLoader. Probably other languages too, but they stick with some default implementation.

And, while we're at this. It would have been nice if __autoload loaded any type of symbols, not just classes: constants, functions and classes.

Ionuț G. Stan
A: 

Both Ruby and PHP get it from AUTOLOAD in Perl.

Note that the AutoLoader module is a set of helpers for common tasks using the AUTOLOAD functionality.

Andy Lester
+1  A: 
  1. Do not use __autoload(). It's a global thing so, by definition, it's somewhat evil. Instead, use spl_autoload_register() to register yet another autoloader to your system. This allows you to use several autoloaders, what is pretty common practice.
  2. Respect existing conventions. Every part of namespaced class name is a directory, so new MyProject\IO\FileReader(); should be in MyProject/IO/FileReader.php file.
  3. Magic is evil!

    The Mitten::factory method can say to itself, "let's see, do I have a subclass called Toast_Mitten()? If so, I'll return that; if not, I'll just return a generic instance of myself - a standard mitten. Oh, look! __autoload() tells me there is a special class for toast. OK, here's an instance!"

    Rather such tricky code, use simple and verbose one:

    try {
        $mitten = new ToastMitten();
        // or $mitten = Mitten::factory('toast');
    } catch (ClassNotFoundException $cnfe) {
        $mitten = new BaseMitten();
    }
    
Crozin
Good points, but I don't necessarily agree with your example in #3. I can't give specific examples, but I'm familiar with a business case where the standard mitten, so to speak, is fine for many departments, at least initially, but any or all of them could eventually want a custom mitten. Say we need to loop through all departments and deploy the appropriate mitten. It's nice to be able to create a new Accounting_Mitten class, if necessary, and have it be automatically used for them, instead of having multiple try/catches or case statements in the factory that need updating.
Nathan Long