PHP Developer / Blog

June
25th, 2008

Stop including class files and use __autoload() instead

Digg this article · Save to del.icio.us · Stumble it!

PHP added several magic methods in PHP5.  __autoload(), however, isn’t one of them.  But that doesn’t make it any less useful.  In fact it’s one of the gems in PHP that I find to be relatively under used.  It’s common for PHP applications to break out classes into their own files.  This becomes cumbersome when working on large projects as you wind up with numerous include/require calls for any given page.  There’s got to be a better way…

Consistency is your friend
I’m sure you name your class files consistently so you can probably skip this section.  Apparently, since you’re reading this, you do not have any rhyme or reason for your class file names.  It doesn’t really matter what it is as long as it’s consistent and predictable.  For example, EpiCode contains a models directory which contains all of the PHP class files.  The file names follow the pattern ClassName.php.  I know that class A is defined in models/A.php.

What can __autoload() do for you?
Did you know that PHP will call __autoload() if you try to call a function which is not yet defined?  You simply have to define it and let it know where to find the class file.  Let’s use my example of placing all class definitions inside a models directory with the filename being the same as the class name.  Your __autoload() function may look something like this.

function __autoload($className)
{
  require_once "./models/{$className}.php";
}

// Instantiate class A without including it and __autoload() will do so on your behalf
$ClassA = new A();

Make your code less ugly
If you can’t spare an extra function call here or there then __autoload() may not be for you. Though I would begin to question your reasoning. The upside is that your code could become significantly cleaner and more maintainable. The upside of easy to read code often trumps everything else.

19 Responses to “Stop including class files and use __autoload() instead”

  1. troelskn Says:

    > The file names follow the pattern ClassName.php. I know that class A is defined in models/A.php.

    You would, except for the fact, that classes are case-insensitive in PHP and file names are case-sensitive on most OS’es. So what you should do, is lower case all file/dir names and do the same in __autoload().

    Also note, that the de-facto convention for class name => file name, is to replace underscores with slashes. So the class model_A would be mapped to model/a.php

  2. H Says:

    Anyone know which would have a smaller overhead: using require_once() vs. checking if the class exists with class_exists ?

  3. Peter Says:

    Wouldn’t it be better to populate your include_path properly, and not hardcode paths in autoload?

    As for the de-facto convention I’ve only seen that in Zend Framework, and it’s something I feel is a result of PHPs lack of namespaces more then anything else.

  4. troelskn Says:

    > As for the de-facto convention I’ve only seen that in Zend Framework, and it’s something I feel is a result of PHPs lack of namespaces more then anything else.

    They borrowed the standard from PEAR. Since PEAR has been around for a long time, it has been used as a standard in many places.

    You’re right, that the conventions stems from PHP’s lack of namespaces, even though it doesn’t really solve that problem entirely.

  5. Talyp Says:

    Thanks. I did not know about it.

  6. Robin Says:

    An alternative to __autoload() is spl_autoload_register(), which can operate with a sequence of loader objects and/or classes - so the same kind of this, just smarter :)

    hth
    –Robin

  7. klkl Says:

    There’s no need to do class_exist(), because __autoload is called _only_ when class does not (yet) exist.

    if you use absolute path (dirname(__FILE__) in require_once it will be slightly faster, because it won’t check include path directories.

    strtolower() on class name is a good idea - class names in PHP are case-insensitive, but Linux filesystems are not (and this will bite you when you develop on Windows or OS X)

  8. Binny V A Says:

    I have started using this recently - its very useful. Also, the files are loaded only if needed - so memory is conserved.

  9. jaisen Says:

    @troelskn, I tend to write code as if PHP (and the underlying OS) were case sensitive. It hadn’t crossed my mind before that class A and class a defined in A.php and a.php respectively could cause lots of headaches :).

    I hope I’d never run into that anyways.

  10. troelskn Says:

    > It hadn’t crossed my mind before that class A and class a defined in A.php and a.php respectively could cause lots of headaches

    A more realistic scenario would be, that you have defined class FooBar in FooBar.php, and write some code like this:
    $f = new Foobar();

    This will trigger __autoload() to load up Foobar.php, which doesn’t exist (It’s FooBar.php). Not entirely far fetched.

  11. Marc Says:

    Failing to load Foobar.php when the file is called FooBar.php is in my opinion a good thing. In my world, the class filename and the class name are identical (except for the .php extention). Makes autoloading by convention straight forward.

    I’ve never understood the argument “keep your files in lower-case because the OS is case-sensitive).

  12. troelskn Says:

    @Marc But you’re _not_ trying to load a file; You’re trying to instantiate a class. It is valid PHP syntax, to write the classname in whichever case, you want. So you will get no error on Windows, but you would on unix. That makes your program non-portable. That’s a pretty good reason in my book.

  13. Jasper Says:

    I love the autoload function, but have found it quite difficult to convince people of its benefits!

    I personally do what troelskn said in the first comment - lowercase all directories and filenames, classes are like Model_Core and User_Model are in core/model.php and model/user.php for portability - never know what sort operating systems clients are going to be using on their servers!

  14. wesley Says:

    What about APC and others, will they still be able to optimize/cache php requests equally well as when you use require?

  15. Mike Cubes Says:

    @troelskn Just because it is valid PHP to write a class name in whatever case you want to at the time, doesn’t mean it is a good idea. Writing all your code under the assumption that the language and the OS are both case-sensitive is a great way to have maintainable, portable, well written code. Yes, I know that PHP is case-insensitive, but that doesn’t mean we as developers have to be. Defining MyClass, then using myClass looks amateur and doesn’t follow a consistent pattern. The hack of running strtolower() inside of __autoload() to account for lazy programmers seams like a waste of a function call to me.

  16. Peter Mescalchin Says:

    @wesley - __autoload() doesn’t do the require/include itself, you need to define the function - which in most cases will wrap a require/include call - so to answer your question, yes APC/eAccelerator will still function - its still require/include under the covers.

    Another great thing with __autoload() it works with ‘extends’… e.g.

    class myclass extends baseclass {}

    __autoload() will be called for both ‘myclass’ and ‘baseclass’.

    I do a similar system to “troelskn/PEAR”, using underscores to name my classes, then breaking that down into subfolders in my class folder. One file per class works really well for me. __autoload() is a godsend.

  17. jaisen Says:

    @Peter, I know internally here at Yahoo there’s been some discussion on times when apc does not cache require/include calls. I don’t want to speak out of ignorance because I can’t remember the specifics but I thought it had to do with dynamically created paths. I want to find out for sure…I’m sure it’ll be another blog post of it’s own as that’s a very important behavior to understand.

  18. jaisen Says:

    @Mike, While I see troelskn’s point…I’m going to have to agree with you on this one. The points he brings up are extremely valid but I don’t think this specific case is the best example of when the case insensitivity of PHP can “taken advantage of”.

  19. Peter Mescalchin Says:

    @jaisen: I remember reading similar reports with APC. With eAccelerator at least hits are certainly made to the bytecode cache when using this method after checking its stats.

    I think the issue with APC might be to do with paths to scripts being relative, rather than absolute, which would be a problem __autoload() or not. The autoload wrapper I use uses a full path from the root of the file system - so maybe that’s why I am having success?

Leave a Reply

Captcha
Enter the letters you see above.


About this site:
This is my (Jaisen Mathai) personal site for potential employers who want to see my resume or portfolio. My ideal job would be to work as a PHP developer on a large scale consumer website. My experience is in using PHP, MySQL, Ajax and JSON. I really enjoy creative brainstorming...taking a problem apart and narrowing 100 solutions down to the best one.

Thanks for stopping by. Be sure to drop me a line.