PHPのフレームワーク内部で使わているautoload処理 これって実際どうなってるの?使うメリットあるの?それにパフォーマンスは?とか 思ったりすると思います!(特にないかもしれません)

今回は、人に説明する時調査しなおした内容も含めてまとめてみたいと思います。

まずは、メリットはあるのか?の説明と、autoloadの処理についての説明も

こんなプログラムをかいていませんか?

<?php
require('./hoge.php');
$hoge = new Hoge();
echo $hoge;
?>

よくあるrequireして、インスタンス作成して実行って流れなんですけど ソースコードの量が増えてきたとき、requireするclassの量が増えてきたとき すんんんんんごいめんどいですよね

<?php
require('./hoge1.php');
require('./hoge2.php');
require('./hoge3.php');
require('./hoge4.php');

$hoge = new Hoge();
echo $hoge;
?>

こんな感じで、、、めんどい! それにフレームワークとかだと、他のコード内ですでに定義済みなのかとか分からない。。 にじゅう requireはおこられちゃう。。

そんな時にautoloadが大活躍

作成するファイルは test.php TestClass.php の二つです。

  1 <?php                                                                        
  2 function autoload($className) {                                              
  3     $chunks = explode('_', 'Dummy_Sample_Class_Name');                       
  4     $path   = implode('/', $chunks);                                         
  5     if ( is_readable($path) ) {}                                             
  6     echo "未定義の[$className]が呼び出されたので、autoloadイベントが発火 \n";
  7     require('./'.$className.'.php');                                         
  8 }                                                                            
  9 spl_autoload_register('autoload');                                           
 10                                                                              
 11                                                                              
 12 echo "未定義クラスのインスタンスを作成すると\n";                             
 13 $sample = new TestClass();                                                   
 14 echo "\n";                                                                   
 15 echo $sample->disp();                                                        
 16 echo "\n";                                                                   
 17 echo "定義済みクラスのインスタンスを作成すると\n";                           
 18 $sample = new TestClass();                                                   
 19 echo $sample->disp();                                                        
 20 echo "\n";                                                                   
 21 echo "テスト完了";                                                           
 22 ?>                                                                           
 23                                                                              

TestClassは、TestClass.phpに記述

  1 <?php
  2 class TestClass {
  3     public function __construct() {
  4         echo __CLASS__ , "インスタンス作成実行";
  5     }
  6 
  7     public function disp() {
  8         return __CLASS__."の".__METHOD__."を実行";
  9     }
 10 }
 11 echo "TestTestクラスの定義完了";

ではでは実行してみます。

$ php test.php
未定義クラスのインスタンスを作成すると
未定義の[TestClass]が呼び出されたので、autoloadイベントが発火 
TestTestクラスの定義完了TestClassインスタンス作成実行
TestClassのTestClass::dispを実行
定義済みクラスのインスタンスを作成すると
TestClassインスタンス作成実行TestClassのTestClass::dispを実行
テスト完了

こんな感じでrequireしてないファイルのクラスを実行したときに、autoloadイベントが発火して、requireをしてくれます。 そのおかげで、requireをなんども書いたりする必要がなくなりました。

こんな感じで、説明は手抜き感満載ですが、autoloadの仕組みを纏めました。

つぎは、動きとメリットはわかったけど、、パフォーマンスはどうなのよホントのところ!!

ではでは、パフォーマンスの程を 検証方法は、100000ファイルがそれぞれ1つのクラスをrequireして、実行したらどれくらいのパフォーマンスが出るのか!! をやってみたかったのですが、ちょっと準備があれなので

100000回ループを回して、require -> new -> 実行を行うという事を検証しました。

requireを毎回するバージョン
<?php

for($i=0;$i<100000;$i++){
    require_once('./TestClass.php');
    $sample = new TestClass();
    $sample->disp();
}
echo 'Memory: '.memory_get_usage()."\n";
autoloadでrequireをするバージョン
<?php
function autoload($className) {
    require('./'.$className.'.php');
}
spl_autoload_register('autoload');

for($i=0;$i<100000;$i++){
    $sample = new TestClass();
    $sample->disp();
}
echo 'Memory: '.memory_get_usage()."\n";

では実行

まずは、requireするするバージョン

$ time php require_once.php 
Memory: 670080

real    0m1.427s
user    0m0.597s
sys 0m0.816s

ぶむふむ では次

$ time php autoload.php     
Memory: 672784

real    0m0.195s
user    0m0.177s
sys 0m0.015s

め、、めっちゃ早い!!

ま、そうですよね、毎回requireを実行してる分重たいですよね。。

今回のテストでは異常な差がでましたが、 フレームワークなどで様々なcontroller,modelが同じLibraryや、Exceptionファイルなどをrequireする事はよくよくある事だと思います。 そんな時は、この結果とまではいかないものの、requireコストがかかってしまっているので、autoloadを使うと無駄な読み込みがへるよって話。。

追伸:大抵のフレームワークでは、autoloadの仕組みは標準で備わっているため、意識することがすくないかもしれません笑

以上、大雑把なてきとう解説、てきとうテストでした。