Jump to content

Autoload vs. require_once performance-wise


avinoamr

Recommended Posts

We had a huge discussion about it at the office, and wanted your advice. Consider a very large-scale MVC web application (over 3000 files, atleast 2000 files in different files), which of the two methods will be more high-performance? (for argument purposes, forget dev-time or complexity, only interested about speed.)

 

1. Creating a huge array with 'ClassName' => 'ClassPath.php', and then use __autoload to require_once the class definition file according to that array.

 

2. For each file, write a list of require_once that is required for that script/file/object to fully work? Also keep in mind that the list will include ALL of the files that are needed for that class, regardless of which functions were actually used.

 

What do you think?

Link to comment
Share on other sites

Seems that doing the latter (require_once each time) is a bit faster. Put together some test scripts and made 998 classes, each in their own file, and then timed __autoloading each class and then require_once-ing each class. Here is what I did, specifically.

 

1. I made a function to generate a file name (and class name) and then looped to make 1000 different php files, and store them in array, name=>file.

2. When it finished making those files, it prints out a string formatted like an array creation string ('something' => 'something else', ...), which I copied to make an array in a new script.

3. For the require_once, I looped through the above array and included each file, immediately afterward adding a new object to an array.

4. I microtimed each file inclusion method individually; here are the results:

 

Note: I had to delete 2 of the classes because they were randomly named 'use' and 'try', which are reserved...

 

I restarted my server after each trial...

 

__autoload each

-----------------

0.115617036819

0.177067041397

0.110083890915

0.134618959427

0.148484945297

 

require_once each

-----------------

0.124009132385

0.120284080505

0.106649875641

0.103686809542

0.103996038437

 

Soooo yeah.

 

EDIT: test script stuff

class timer {
  public function timer() {
    $this->resume = $this->cur_time();
    $this->pause = 0;
    $this->state = TRUE;
    $this->total = 0;
  }
  
  private function cur_time(){
    $time = explode(' ', microtime());
    return $time[1].substr($time[0], 1);
  }
  
  public function pause() {
    if ($this->state) {
      $this->pause = $this->cur_time();
      $this->total = $this->pause - $this->resume;
      $this->state = FALSE;

      return $this->total;
    }
  }
  
  public function resume() {
    if (!$this->state) {
      $this->resume = $this->cur_time();
      $this->state = TRUE;
    }
  }
}

/* 
* File gen
* 
function fill($len) {
    $chars = "abcdefghijkmnopqrstuvwxyz";
    $i = 0;
    while ($i < $len) {
        $fill = $fill.substr($chars, rand(0,24), 1);
        $i++;
    }
    return $fill;
}

$huge = array();

$i = 0;
while ($i < 1000) {
$name = fill(3);
  if (!file_exists("lots_o_files/".$name.".php")) {
    $file = fopen("lots_o_files/".$name.".php", "w");
    fwrite($file, "<?php class $name { function $name(){} } ?>");
    fclose($file);
    $huge[$name] = $name.".php";
    $i++;
  }
}

foreach ($huge as $name => $file) {
echo "'$name'=>'$file', ";
}

echo "<br />";

foreach ($huge as $name => $file) {
echo "require_once 'lots_o_files/$file';";
}
*/

// Listed all 998 classes.
$classes = array('cmh'=>'cmh.php', 'jnj'=>'jnj.php', 'dur'=>'dur.php', 'hze'=>'hze.php', ....);

// __AUTOLOAD TEST

$autoload = new timer();

function __autoload($name) {
  global $classes;
  require_once 'lots_o_files/'.$classes[$name];
}

foreach ($classes as $name => $file) {
  $class[] = new $name;
}

echo $autoload->pause();


// REQUIRE ONCE TEST
/*
$require = new timer();

foreach ($classes as $name => $file) {
  require_once 'lots_o_files/'.$file;
  $class[] = new $name;
}

echo $require->pause();
*/

Link to comment
Share on other sites

What you've failed to take into account in the test is the way that this will work.

With __autoload() it is fired every time a class is "not known about". Thus only a require_once is done ONCE for each class.

Whereas if you have lots of classes each with their own dependencies (i.e. each class has the files it requires listed in it as in method 2) you have the overhead call of a require_once() for EVERY class file you use, regardless of whether you have already loaded that class or not.

 

Thus the test below is skewed because it implies that a require_once is performed only once (which is not true for the 2nd method).

 

Also from another point of view (and off-topic because you were discussing speed), I personally would HATE to have to know what each file required, and maintaining that in 2000 class files is just ridiculous. __autoload() is a winner in my eyes...

Link to comment
Share on other sites

Thank you Alecks, your method seemed to do the work. Only thing to note though, is that in your test you've included all of the classes, but in-fact __autoload will only include the needed ones. The require_once approach will included all of the files needed throughout the class, __autoload will only create the ones needed by the specific workflow (functions, conditions, etc.). For example, let's consider the following class:

 

class ClassName() {

 function Func1() {
   // uses class1.php
 }

 function Func2() {
   // uses class2.php
 }

 function Func3() {
   // uses class3.php
 }

}

 

If we only execute ->Func3(), autoload will only include class3.php, require_once will include all three files.

 

keebB, regarding the debugging issue, I just suggest extremely secure code. The function should throw detailed exceptions about every little issue (class in array, file exists, include failed, class exists, anything else?), making it impossible to miss anything.

 

Overall I agree with aschk, that when it comes to maintainability and rapid development, __autoload is a great tool, even at the expense of a minor performance reduction. Only problem I see with coding practices with __autoload, is that a careless programmer might use too many different classes for simple operations that doesn't really require all of these classes. With require_once you can't miss the fact that you need to use a different class file and with __autoload it's easy to get forgetful. Makes sense?  8)

Link to comment
Share on other sites

Using alecks' test results, I did some math.

 

The avg. time with __autoload() was  0.137174374771

The avg. time with require_once() was 0.111725187302

 

This means under the test conditions (loading the exact same files), __autoload() is 22.778% slower.

Link to comment
Share on other sites

<?
// Constants:
define ('DIRSEP', DIRECTORY_SEPARATOR);
// Get site path
$site_path = realpath(dirname(__FILE__) . DIRSEP . '..' . DIRSEP);
define ('SITE_PATH', $site_path);

function __autoload($class_name) {
$filename = strtolower($class_name) . '.class.php';
$file = SITE_PATH . 'classes' . DIRSEP . $filename;
if (file_exists($file) == false)
 {
      return false;
 }
include ($file);
}

?>

 

That's my autoload class - all it does is every time I type

$var = new {classname};

It automatically loads classes/classname.class.php, no need for an array.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.