Wednesday, April 25, 2012

How unique is PHP"s __autoload()?


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



  • You try to use a class, like new Toast_Mitten() (footnote 1 )

  • 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?


Source: Tips4all

5 comments:

  1. Both Ruby and PHP get it from AUTOLOAD in Perl.


    http://perldoc.perl.org/perltoot.html#AUTOLOAD:-Proxy-Methods
    http://perldoc.perl.org/AutoLoader.html


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

    ReplyDelete
  2. 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.
    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.
    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();
    }

    ReplyDelete
  3. 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.

    ReplyDelete
  4. 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.

    ReplyDelete
  5. See Ruby's Module#const_missing

    I just learned this: Ruby has a method on Module called const_missing that gets called if you call Foo::Bar and Bar isn't in memory yet (although I suppose that Foo has to be in memory).

    This example in ruby-doc.org shows a way to use that to implement an autoloader for that module. This is in fact what Rails uses to load new ActiveRecord model classes, according to "Eloquent Ruby" by Russ Olsen (Chapter 21, "Use method_missing for flexible error handling", which also covers const_missing).

    It's able to do this because of the "convention over configuration" mindset: if you reference a model called ToastMitten, if it exists, it will be in app/models/toast_mitten.rb. If you could put that model any place you wanted, Rails wouldn't know where to look for it. Even if you're not using Rails, this example, and point #1 in my question, shows how useful it can be to follow conventions, even if you create them yourself.

    ReplyDelete