2009-08-31 14 views
12

私はちょうどphpのautoload()関数を見てきました。いいアイデアだと思いますが、複数のディレクトリをどのように扱うかはわかりません。私の現在の開発では、基本的に、操作によってクラスをサブディレクトリにグループ化するライブラリディレクトリ構造があります。私はそれぞれのディレクトリにinclude()を宣言しなければならないと思っています...本当に私がする必要はありません。自動ロードと複数のディレクトリ

アドバイスありがとうございます。

答えて

1

残念ながら、各ディレクトリを明示的に追加する必要があります。これは、ディレクトリを再帰的に横断するスクリプトでプログラムで実行することも、リストを指定することもできます。

おそらく最も効率的な方法は、検索するディレクトリとサブディレクトリのリストを指定し、これらをini_set()を使用して 'include_path'に追加することでしょう。

17

クラス名についてはPEAR Conventionを見てみるといいでしょう。これは本当にオートロードには最適です。

PEARクラス階層は、クラス名に反映 、 単一下線で分離階層の各レベル ある:

は基本的には、と述べています。

これは、クラッセ名HTML_Upload_Errorに含めるファイルを見つけることは、 '_'を '/'で置き換えることに過ぎません。あなたはより多くの説明、および例のカップルのためHTML/Upload/Error.php

を与え、あなたは記事を見てとることができます。この規則は、によって使用されます。ところで

多くの大きなフレームワーク/ライブラリ;-)
たとえば、Zend Frameworkではこのコンベンションが使用されています。

+0

私はこのメソッドがうまく動作することを発見しました。私が使った別の方法は、上記の方法が適用されるルートディレクトリを指す静的パッケージをフォルダマップに使用することです。 –

+2

__autoloadについてよく説明している素晴らしい説明リンクのための+1:http://blog.straylightrun.net/2009/05/06/autoload-magic/ –

1

あなたは混乱しているように見えます:)または、おそらく私はあなたの質問で混乱しています。

クラスの検索と読み込みを行う関数を書くのはあなたの責任です。PHPはどこに何階層あるのか気にしません。

SPL autoload tooを見ると、基本機能は同じですが、複数のオートロード機能を記述してからチェーンすることができます。いくつかの外部ライブラリを使用したい場合は、自分のオートローダーを定義することで、自分のものと競合する可能性があります。

1

PHPのSPLオートロード機能について話していると思います。あなた自身の機能を記述して、それをSPLに登録します。

どのようにするかは、インクルード関数をどのように作成するかによって異なります。複数のインクルード関数を宣言してPHPで登録することができます。 SPLオートロード機能は、あなた自身の関数を作成して、クラスに必要なたびにその関数を実行するようにPHPに指示するだけです。

複数作成するメリットの1つは、最も使用頻度が最も低いディレクトリから順に使用順に登録する機能です。また、ディレクトリが変更または削除された場合は、責任のある機能を簡単に変更および/または削除します。

フォルダ構造全体を処理する関数を書くこともできます(ただし、管理とコードのデカップリングを簡単にするためには推奨しません)。それを行う "技術的に正しい"方法はありません:)

10

これは私が同じような目的のためにしばらく前に書いたクラスです。その時私はまだ学習段階にあったので、愚かな考えが関わっているかもしれません。それにもかかわらず働いた。

基本的な考え方は、ソースディレクトリを一度スキャンして、クラスをソースファイルにマッピングする配列を作成することです。クラスはオートローダーとして登録され、呼び出されると必要なファイルが含まれます。見つからなければ、アレイを即座に再構築しようとします。

/* register ClassLoader as class loader */ 
spl_autoload_register(array(ClassLoader::getInstance(), 'loadClass')); 


class ClassLoader { 

    private static $SAVE_FILE = 'ClassLoader.save.php'; 

    /* singleton */ 
    private static $instance; 

    /* stores a className -> filePath map */ 
    private $classList; 
    /* tells whether working from saved file */ 
    private $refreshed; 


    public static function getInstance() { 
     if (!isset(self::$instance)) { 
      self::$instance = new ClassLoader(); 
     } 
     return self::$instance; 
    } 

    private function __construct() { 
     $this->initClassList(); 
    } 

    public function loadClass($className) { 
     if (!array_key_exists($className, $this->classList) && !$this->refreshed) { 
      $this->refreshClassList(); 
     } 
     require_once($this->classList[$className]); 
    } 

    private function initClassList() { 
     if (file_exists(INCLUDES_DIR . self::$SAVE_FILE)) { 
      require_once(INCLUDES_DIR . self::$SAVE_FILE); 
      $this->refreshed = FALSE; 
     } else { 
      $this->refreshClassList(); 
     } 
    } 

    private function refreshClassList() { 
     $this->classList = $this->scanDirectory(INCLUDES_DIR); 
     $this->refreshed = TRUE; 

     $this->saveClassList(); 
    } 

    private function saveClassList() { 
     $handle = fopen(INCLUDES_DIR . self::$SAVE_FILE, 'w'); 
     fwrite($handle, "<?php\r\n"); 

     foreach($this->classList as $class => $path) { 
      $line = '$this->classList' . "['" . $class . "'] = '" . $path . "';\r\n"; 
      fwrite($handle, $line); 
     } 

     fwrite($handle, '?>'); 
     fclose($handle); 
    } 

    private function scanDirectory ($directory) { 
     // strip closing '/' 
     if (substr($directory, -1) == '/') { 
      $directory = substr($directory, 0, -1); 
     } 

     if (!file_exists($directory) || !is_dir($directory) || !is_readable($directory)) { 
      return array(); 
     } 

     $dirH = opendir($directory); 
     $scanRes = array(); 

     while(($file = readdir($dirH)) !== FALSE) { 

      // skip pointers 
      if (strcmp($file , '.') == 0 || strcmp($file , '..') == 0) { 
       continue; 
      } 

      $path = $directory . '/' . $file; 

      if (!is_readable($path)) { 
       continue; 
      } 

      // recursion 
      if (is_dir($path)) { 
       $scanRes = array_merge($scanRes, $this->scanDirectory($path)); 

      } elseif (is_file($path)) { 
       $className = explode('.', $file); 
       if (strcmp($className[1], 'class') == 0 && strcmp($className[2], 'php') == 0) { 
        $scanRes[$className[0]] = $path; 
       } 
      } 
     } 

     return $scanRes; 
    } 

} 
+0

すばらしいClassLoader。 – Jerska

1

すでに述べたように、SPLオートローディングは、機能的には、あなたが実用的な実装を移植する必要があり、その上に構造体である - ディレクトリトラバーサルと命名規則は、これらの考慮事項の一部です。

は、Zendローダーの形で実用的な例を見てみましょう:その根拠で、これはPHPのに登録されているディレクトリに相関する名前空間の規則を使用シングルトンであるパスが含まれています。実用例:

set_include_path(get_include_path(). PATH_SEPARATOR. 'App/'); //Concat the "App" directory onto the existing include paths 
$loader = Zend_Loader::getInstance(); //because the autoloader is a singleton, we get a reference to it without assuming we need to first create it 
$loader->registerNamespace('App_'); //Tell autoloader it can look in the app directory to find classes if it can't find them in the default Zend directory. 

明らかに特定の実装上の問題が突出したプロジェクトによって異なりますが、それは理解の練習として、コードの再利用のために、両方の、最高であってもよいし、解析することができオートローダーをプログラミングであなたの手をしようとします特定のクラス形式(例えば 'directory_classname')をディレクトリマップに追加し、クラスをロードして検証します。