본문 바로가기
개발/PHP

__autoload() - 2

by GetLight 2010. 3. 24.
include_path 개념
지금 리눅스/유닉스를 사용하고 계시거나, 예전에 DOS를 사용해 보셨다면, PATH환경 변수에 대해서 알고 있을 겁니다.
파일을 include시 꼭 현재 스크립트로 부터 시작되는 상대경로가 아니더라도, include path안에 있는 경로이면 알아서 include를 시켜줍니다.

메뉴얼에 따르면
require()와 include(), fopen_with_path() 함수들이 사용하는 파일을 찾을 위치(path)를 지정한다. string의 형식은 시스템 환경변수 PATH의 설정과 비슷하다. UNIX에서는 콜론으로 나뉘어진 디렉토리들의 리스트이고, Windows에서는 세미콜론을 사용한다. (이하 생략)

즉, 자동으로 파일을 찾아 include시켜준다는 의미 입니다. 이것을 조작하는 방법은 몇가지가 있는데,
  • php.ini에서 직접 변경
  • ini_get, ini_set 함수
  • get_include_path, set_include_path 함수
저는 php.ini에서 직접변경하는 방법과 함수를 사용하는 방법 중 함수를 사용해 동적으로 변경시키는 방법을 선호합니다. 왜냐하면 한 서버에서 여러개의 프로그램을 사용할 것이고, 또 개발서버에서 운용서버로 소스를 옮길 때 php.ini파일을 개발서버에 맞춰 변경시켜야 하는 번거로움이 싫어서입니다.

ini_get과 ini_set은 설정 옵션을 조정할 수 있도록 하는 범 용함수이고, get_include_path와 set_include_path는 php4.3이상에서 지원하는 include_path를 위한 전용함수 입니다. 사용 예는 메뉴얼에서 확인 하실 수 있습니다.

아래 코드에서는 set_include_path와 get_include_path를 사용합니다.

그러면 include_path을 지정하면서 __autoload가 실행되는 것을 보겠습니다.


function __autoload($className) {
   $toSetIncludePath =     './app'.PATH_SEPARATOR.
                           './libs'.PATH_SEPARATOR.
                           './libs/Pear'.PATH_SEPARATOR.
                           './libs/ThirdParty'.PATH_SEPARATOR.
                           './app/Controller'.PATH_SEPARATOR.
                           './app/DataObject'.PATH_SEPARATOR;

   set_include_path( $toSetIncludePath .PATH_SEPARATOR.get_include_path());
/*PATH_SEPARATOR는 윈도환경에서는 세미콜론(;), xNIX환경에서는 콜론(:)이 저장되어 있는 PHP기본 상수입니다. */
  $path = str_replace('_',DIRECTORY_SEPARATOR,$className).'.php';
/*DIRECTORY SEPARATOR는 윈도환경에서는 \으로, xNIX환경에서는 / 이 저장되어 있는 php기본 상수 입니다.
*/

   require_once $path;
}


이 코드를 통해 이제 __autoload가 실행이 되면 자동으로 include_path를 따라 다른 경로에 있는 패키지들도 include가 가능하게 되었습니다.

하.지.만 이 방법도 문제가 있습니다. 상황에 따라 다르겠지만 저의 경우는 패키지 내에서 include할 때(cohesion)를 제외하고는 거의 include를 사용하지 않으므로 한 스크립트가 실행될 때 __autoload가 여러번 실행되게 됩니다.
그래서 위와 같은 방법으로는 include_path를 지정해주는 코드가 여러번 실행되는 것을 피할 수가 없게 됩니다.

그래서 정적(static)변수를 사용해 아래와 같이 개선해보았습니다.
function __autoload($className)
{
   static $isInit= FALSE;
   if( !$isInit) {
       __autoload_init();
       $isInit= TRUE;
   }
  $path = str_replace('_',DIRECTORY_SEPARATOR,$className).'.php';
/*DIRECTORY SEPARATOR는 윈도환경에서는 \으로, xNIX환경에서는 / 이 저장되어 있는 php기본 상수 입니다.*/
   require_once $path;
}
function __autoload_init()
{
   $strToSetIncludePath =     './app'.PATH_SEPARATOR.
                           './libs'.PATH_SEPARATOR.
                           './libs/Pear'.PATH_SEPARATOR.
                           './libs/ThirdParty'.PATH_SEPARATOR.
                           './app/Controller'.PATH_SEPARATOR.
                           './app/DataObject'.PATH_SEPARATOR;

   set_include_path($strToSetIncludePath.PATH_SEPARATOR.get_include_path());
/*PATH_SEPARATOR는 윈도환경에서는 세미콜론(;), xNIX환경에서는 콜론(:)이 저장되어 있는 PHP기본 상수입니다. */
}

제가 지금 사용하는 코드가 바로 위와 비슷한 코드 입니다. 파일이 존재하지 않을 때를 대비한 예외처리까지 합하면 조금 더 길어지기는 하지만.. 예외처리가 쉽게 가능하도록 아래에 팁을 마련합니다. 참고하시고 잘 사용하셨으면 좋겠습니다^^
include_path에서 파일이 있는지 없는지 어떻게 알 수 있을까?
file_exists를 이용한 노가다를 할 수도 있지만.. 조금더 elegant한 방법은,
fopen을 실행시켜 리턴값이 resource인지를 확인하는 방법이다. 많이 사용되지 않는 fopen의 세번째 인자는 include_path를 활용할 것인가 하는 boolean값이다.(기본값은 false다)

태그

,