PHP에 필요한 클래스 포함을 처리하는 방법
문제
내가 사용해야 하는 모든 클래스가 내 스크립트에 액세스할 수 있도록 하기 위해 PHP 스크립트에 너무 많은 파일을 "포함"해야 하는 문제를 처리하는 가장 좋은 방법이 무엇인지 궁금합니다.
현재는 그냥 사용하고 있어요 include_once 내가 직접 액세스하는 클래스를 포함합니다.그 각각은 include_once
액세스하는 클래스.
사용방법을 살펴봤는데 __autoload
기능이 있지만 클래스 파일을 디렉토리 트리에 구성하려는 경우 hat이 제대로 작동하지 않는 것 같습니다.이렇게 하면 원하는 클래스를 찾을 때까지 디렉토리 트리를 탐색하게 될 것 같습니다. 또한 이것이 다른 네임스페이스에서 동일한 이름을 가진 클래스에 어떤 영향을 미치는지 잘 모르겠습니다.
이 문제를 처리하는 더 쉬운 방법이 있습니까?
아니면 PHP가 "기업적인" 다양한 디렉터리에 있을 수 있는 별도의 파일에 있는 다양한 개체가 있는 애플리케이션 유형입니다.
해결책
나는 평소에 갖고 있는 애플리케이션 setup.php
모든 핵심 클래스를 포함하는 파일(예:프레임워크 및 관련 라이브러리).내 사용자 정의 클래스는 디렉토리 레이아웃 맵의 지원을 받는 자동 로더를 사용하여 로드됩니다.
새 클래스가 추가될 때마다 모델 클래스를 검색하기 위해 전체 디렉토리 트리를 스캔한 다음 클래스 이름을 키로, 경로를 값으로 사용하여 연관 배열을 작성하는 명령줄 작성기 스크립트를 실행합니다.그런 다음 __autoload 함수는 해당 배열에서 클래스 이름을 조회하고 포함 경로를 가져옵니다.코드는 다음과 같습니다.
autobuild.php
define('MAP', 'var/cache/autoload.map');
error_reporting(E_ALL);
require 'setup.php';
print(buildAutoloaderMap() . " classes mapped\n");
function buildAutoloaderMap() {
$dirs = array('lib', 'view', 'model');
$cache = array();
$n = 0;
foreach ($dirs as $dir) {
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir)) as $entry) {
$fn = $entry->getFilename();
if (!preg_match('/\.class\.php$/', $fn))
continue;
$c = str_replace('.class.php', '', $fn);
if (!class_exists($c)) {
$cache[$c] = ($pn = $entry->getPathname());
++$n;
}
}
}
ksort($cache);
file_put_contents(MAP, serialize($cache));
return $n;
}
자동로드.php
define('MAP', 'var/cache/autoload.map');
function __autoload($className) {
static $map;
$map or ($map = unserialize(file_get_contents(MAP)));
$fn = array_key_exists($className, $map) ? $map[$className] : null;
if ($fn and file_exists($fn)) {
include $fn;
unset($map[$className]);
}
}
파일 명명 규칙은 [class_name].class.php여야 합니다.디렉토리 클래스를 변경하면 다음에서 검색됩니다. autobuild.php
.클래스를 찾을 수 없을 때 자동 로드 기능에서 자동 빌더를 실행할 수도 있지만 이로 인해 프로그램이 무한 루프에 빠질 수 있습니다.
직렬화된 배열은 매우 빠릅니다.
@제이슨마이클:PHP4는 죽었습니다.극복하세요.
다른 팁
spl_autoload_register를 사용하여 여러 자동 로딩 기능을 정의할 수 있습니다.
spl_autoload_register('load_controllers');
spl_autoload_register('load_models');
function load_models($class){
if( !file_exists("models/$class.php") )
return false;
include "models/$class.php";
return true;
}
function load_controllers($class){
if( !file_exists("controllers/$class.php") )
return false;
include "controllers/$class.php";
return true;
}
물리적 디렉터리에 매핑되는 구조화된 명명 규칙을 사용하여 프로그래밍 방식으로 클래스 파일의 위치를 확인할 수도 있습니다.이것이 Zend가 수행하는 방식입니다. Zend 프레임워크.그래서 전화할 때 Zend_Loader::loadClass("Zend_Db_Table");
밑줄로 나누어 클래스 이름을 디렉터리 배열로 분해한 다음 Zend_Loader 클래스가 필요한 파일을 로드합니다.
모든 Zend 모듈과 마찬가지로 로더만 자신의 클래스와 함께 사용할 수 있을 것으로 기대하지만 저는 Zend의 MVC를 사용하는 사이트의 일부로만 사용했습니다.
그러나 모든 종류의 동적 클래스 로딩을 사용할 때 로드 시 성능에 대한 우려가 있었습니다. 예를 들어 다음을 참조하세요. 이 블로그 게시물 Zend_Loader와 클래스 파일의 하드 로딩을 비교합니다.
PHP 포함 경로를 검색해야 하는 성능 저하뿐 아니라 opcode 캐싱도 무효화됩니다.해당 게시물의 댓글에서:
모든 동적 클래스 로더를 사용하는 경우 APC는 단일 요청에 어떤 파일이 로드될지 확신할 수 없기 때문에 해당 파일을 완전히 캐시할 수 없습니다.APC는 파일을 하드 로딩하여 파일 전체를 캐시할 수 있습니다.
__autoload
클래스가 디렉터리 트리 내에서 발견되는 위치를 함수에 알려주는 일관된 명명 규칙이 있는 경우 잘 작동합니다.MVC는 클래스를 모델, 뷰 및 컨트롤러로 쉽게 분할할 수 있기 때문에 이러한 종류의 작업에 특히 적합합니다.
또는 클래스의 파일 위치에 대한 이름의 연관 배열을 유지하고 __autoload
이 배열을 쿼리합니다.
지금까지의 제안 중에서 나는 Kevin의 제안에 부분적으로 동의하지만 그것이 절대적일 필요는 없습니다.__autoload와 함께 사용할 수 있는 몇 가지 다른 옵션이 있습니다.
- 모든 클래스 파일을 단일 디렉터리에 넣습니다.클래스 이름을 따서 파일 이름을 지정합니다. 즉,
classes/User.php
또는classes/User.class.php
. - 모델을 한 디렉토리에, 컨트롤러를 다른 디렉토리에 넣는 등의 Kevin의 아이디어모든 클래스가 MVC 프레임워크에 잘 맞으면 잘 작동하지만 때로는 상황이 지저분해질 수 있습니다.
- 클래스 이름에 디렉터리를 포함합니다.예를 들어 Model_User라는 클래스는 실제로 다음 위치에 있습니다.
classes/Model/User.php
.__autoload 함수는 파일을 찾기 위해 밑줄을 디렉터리 구분 기호로 변환하는 방법을 알고 있습니다. - 전체 디렉토리 구조를 한 번만 구문 분석하면 됩니다.__autoload 함수에서 또는 정의된 동일한 PHP 파일에서
classes
디렉토리에 어떤 파일이 어디에 있는지 캐시합니다.따라서 로드하려고 하면User
수업을 들어도 상관없어classes/User.php
또는classes/Models/User.php
또는classes/Utility/User.php
.일단 발견되면User.php
어딘가에classes
디렉터리에 포함되면 어떤 파일을 포함할지 알 수 있습니다.User
클래스를 자동으로 로드해야 합니다.
@케빈:
나는 여러 로더를 정의할 수 있고 서로 충돌하지 않기 때문에 spl_autoload_register가 __autoload보다 더 나은 대안이라는 점을 지적하려고 했습니다.__autoload 함수도 정의하는 라이브러리를 포함해야 하는 경우 유용합니다.
확실합니까?그만큼 선적 서류 비치 다르게 말한다:
코드에 기존 __autoload 함수가 있는 경우 이 함수는 __autoload 스택에 명시적으로 등록되어야 합니다.이는 spl_autoload_register()가 __autoload 함수에 대한 엔진 캐시를 spl_autoload() 또는 spl_autoload_call()로 효과적으로 대체하기 때문입니다.
=> 모든 라이브러리를 명시적으로 등록해야 합니다. __autoload
또한.하지만 그 외에도 당신 말이 옳습니다. 이 기능이 더 나은 대안입니다.
__autoload
작동하지만 PHP 5에서만 가능합니다.