2009-08-31 3 views
12

방금 ​​php의 autoload() 함수를 살펴 보았습니다. 좋은 생각 인 것 같지만 여러 디렉토리를 어떻게 처리하는지 잘 모르겠습니다. 현재 개발 중에는 기본적으로 클래스를 하위 디렉토리로 그룹화하여 라이브러리 디렉토리 구조가 있습니다. 각 디렉토리에 대해 include()를 선언해야한다는 것을 알고 싶습니다. 실제로는 할 필요가 없기를 바랍니다.자동로드 및 다중 디렉토리

감사합니다.

답변

1

불행히도 각 디렉토리를 명시 적으로 추가해야합니다. 이 작업은 재귀 적으로 디렉터리를 탐색하는 스크립트에서 프로그래밍 방식으로 수행하거나 목록을 지정할 수 있습니다.

아마도 가장 효율적인 방법은 검색 할 디렉토리 및 하위 디렉토리 목록을 지정하고이를 ini_set()을 사용하여 'include_path'에 추가하는 것입니다.

17

클래스 이름은 PEAR Convention입니다. 자동 로딩에 유용합니다.

배 클래스 계층 구조는 클래스 이름에 반영 , 단일 밑줄로 분리 된 계층 구조의 각각의 레벨 :

는 기본적으로, 상태.

즉, 동격 이름 HTML_Upload_Error에 포함 할 파일을 찾는 것은 '_'을 '/'로 바꾸는 것입니다. 당신에게 HTML/Upload/Error.php

더 설명은

, 그리고 몇 가지 예를 제공, 당신은 기사에서 좀 걸릴 수 있습니다 : BTW

+0

나는이 방법이 잘 작동하는 것을 발견했습니다. 내가 사용한 또 다른 방법은 위의 방법을 적용하는 루트 디렉토리를 가리키는 폴더 맵에 정적 패키지를 사용하는 것입니다. –

+2

__autoload를 잘 설명하는 위대한 설명 링크 +1 : http://blog.straylightrun.net/2009/05/06/autoload-magic/ –

1

당신이 혼란스러워 보입니다 :) 아니면 당신의 질문에 혼란 스럽습니다.

클래스를 찾고로드하는 함수를 작성하는 것은 전적으로 PHP가 어디에서 얼마나 많은 수준인지는 신경 쓰지 않습니다.

SPL autoload too을 살펴보면 기본 기능이 동일하지만 여러 자동로드 기능을 작성한 다음 연결할 수 있습니다. 일부 외부 라이브러리를 사용하려는 경우 자신의 오토로더를 정의하는 것이 유용 할 수 있습니다.

1

필자는 PHP의 자동로드 기능에 대해 이야기하고 있다고 가정합니다. 여기서 자신이 작성한 함수를 작성한 다음 SPL에 등록합니다.

어떻게 수행 하는가는 포함 기능을 만드는 방법에 따라 다릅니다. 여러 개의 include 함수를 선언하고 PHP로 등록하는 것이 가능합니다 : 몇 개가 당신에게 달려 있습니다. SPL 자동로드 기능을 사용하면 자신 만의 함수를 생성 한 다음 클래스에 필요할 때마다 해당 함수를 실행하도록 PHP에 지시 할 수 있습니다.

다중을 만드는 한 가지 이점은 가장 많이 사용되는 디렉토리를 가장 나중에 사용하는 순서대로 사용 순서에 등록 할 수 있다는 것입니다. 또한 디렉토리가 변경되거나 삭제되면 책임있는 기능을 간단히 변경하거나 삭제할 수 있습니다.

전체 폴더 구조를 통과 할 수있는 함수 하나를 작성할 수 있습니다 (관리 및 코드 분리 용이성을 위해 권장하지는 않지만). "기술적으로 올바른 방법"이 없습니다.

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 자동 로딩은 기능적으로는 실제 구현을 접목해야하는 상 구조 - 디렉토리 탐색 및 명명 규칙 이러한 고려 사항의 일부입니다.

젠드 로더의 형태로 실용적인 예를 들어 봅시다 : 기본으로, 이것은 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')을 디렉토리 맵에 추가 한 다음 클래스를로드하고 유효성을 검사합니다.