2011-08-06 3 views
1

현재 HMVC 디자인 패턴을 사용하여 학습용으로 자신의 PHP 프레임 워크를 작성하고 있습니다. 그것은 모든 :) 작동하지만, 나는 내 자동로드 기능에 뭘하는지 정확히 PHP 코드에서 정적 클래스를 참조하는 나쁜 습관이 있다는 여러 번 읽었습니다 : 당신으로특정 폴더에서 모델 클래스를 자동로드하는 가장 좋은 방법 HMVC

function __autoload($className) { 
    $path = SERVER_ROOT . DS . 'applications' . DS . Dispatcher::getApplicationName() . DS . 'models' . DS . 'class.' . strtolower($className) . '.php'; 

    if (file_exists($path)) { 
     require_once($path); 
    } else { 
     throw new Exception('Can\'t find a model at "' . $path . '".'); 
    } 
} 

내가 정적 호출 Dispatcher::getApplicationName()을 사용하여 현재 응용 프로그램을 얻는 것을 볼 수 있습니다. 종속성을 도입 한 이후로 많은 사람들에게 나쁜 것입니다. 또한 모델을 시작하는 클래스에 ApplicationName이 속성으로 포함되어 있기 때문에 debug_backtrace()을 사용하여 applicationName을 가져올 수도 있습니다. 그게 더 낫습니까? 아니면 제가 생각하지 못한 다른 대안들이 있습니까?

감사합니다.

편집 : 위의 코드에 또 다른 문제가 있음을 잊어 버렸습니다. HMVC 디자인 패턴을 사용하고 있으므로 컨트롤러의 애플리케이션이 디스패처의 애플리케이션과 항상 같지는 않습니다 (컨트롤러가 컨트롤러 내부에서 호출되도록). 이것은 debug_backtrace을 사용해서 만 고칠 수 있습니다.

편집 : Dispatcher::getApplicationName() 대신 Request::getCurrentApplicationName()을 사용합니다. 요청 클래스가 모든 응용 프로그램을 저장하기 때문에 이제 다시 작동합니다. 이게 더 나은가요, 아니면 더 좋은 방법이 있습니까?

<?php 

class Request { 
    private static $_controllers = array(); 
    private static $_applicationsNames = array(); 

    public static function _getCurrentApplicationName() { 
     return end(self::$_applicationsNames); 
    } 

    public static function _load($applicationName, $controllerName, $methodName) { 
     // Add the application the the array (for autoloading). 
     self::$_applicationsNames[] = $applicationName; 

     // Check if the controller has already been instantiated. 
     if (!isset(self::$_controllers[$applicationName . DS . $controllerName])) { 
      require_once(APPLICATIONS_ROOT . DS . $applicationName . DS . 'controllers' . DS . 'class.' . $controllerName . '.php'); 
      self::$_controllers[$applicationName . DS . $controllerName] = new $controllerName($applicationName); 
     } 

     // Get the user arguments. 
     $arguments = array_slice(func_get_args(), 3); 

     // Call the method. 
     $result = call_user_func_array(array(self::$_controllers[$applicationName . DS . $controllerName], $methodName), $arguments); 

     // Remove the last value from the applications array. 
     array_pop(self::$_applicationsNames); 
    } 
} 

답변

2

시작 중에 필요한 모든 정보가 포함 된 자동로드 클래스의 정적 멤버를 설정할 수 없습니까?

debug_backtrace()는 신뢰할 수있는 정보 소스가 될 수 없습니다. 어떤 사람이 라이브러리 을 오토로더로 사용하고 싶지만 시작 레이어가없는 경우에는 어떻게해야합니까? 그렇게 할 수 있을까요?

클래스/함수가 사용하는 모든 데이터는 해당 클래스 또는 함수의 매개 변수로 사용해야합니다. 오토로더는 모든 콜백이 될 수 있으므로 다음과 같이 할 수 있습니다.

class FrameworkAutoloader 
{ 
    public $appName; 
    public $path; 

    public function setAppName($name) { $this->appName = $name; } 
    public function setPath($path) { $this->path= $path; } 


    function __autoload($className) { 
     $path = $this->path. DS . 'applications' . DS . $this->appName . DS . 'models' . DS . 'class.' . strtolower($className) . '.php'; 

     if (file_exists($path)) { 
      require_once($path); 
     } else { 
      throw new Exception('Can\'t find a model at "' . $path . '".'); 
     } 
    } 
} 

$autoloader = new FrameworkAutoloader(); 
$autoloader->setAppName('asd'); //you can also apply those within constructor, but leave setters 
$autoloader->setPath('asd'); 
spl_autoload_register(array($autoloader, '__autoload')); 

그게 전부입니다. setter를 사용하여 객체의 변수를 변경하는 것만으로 경로와 appname을 동적으로 설정할 수 있습니다.

왜 이런 식으로해야합니까? 이 코드에는 "마법"이 없습니다. 모든 함수에 PHPDOC을 사용하여 문서를 작성할 수 있으며 사용자는 모든 매개 변수의 출처를 알 수 있습니다. 또 다른 장점은 클래스가 Dispatcher :: getApplicationName()을 사용한다는 것을 알 필요가 없어도 어디서나이 코드를 사용할 수 있다는 것입니다.

+0

즉, 요청 클래스의 모든 요청마다 값을 변경해야한다는 의미입니다. 처음 시작 게시물에서 수정 한 코드보다 실제로 더 낫습니까? – Frog

+0

각 응용 프로그램에 대해 별도의 오토로더를 작성하여 해결할 수 있다고 생각합니다. MyApplication :: install()과 같은 것을 호출 할 등록 메커니즘을 생성하십시오. 이러한 솔루션은 코드에 더 많은 모듈성을 제공합니다. 다른 장점은 다른 응용 프로그램에서 동시에 클래스를로드 할 수 있다는 것입니다 (성능 문제가 발생하기 때문에 어떤 것이 더 중요한지 결정해야합니다). 예 : PollApp은 폴링의 첫 번째 인스턴스에서 PollTextModel을로드 한 다음 NewsApp에서 일부 클래스를로드하고 마지막에는 PollApp이 두 번째 인스턴스에 대해 PollDbModel을로드합니다. –

+0

답변 해 주셔서 감사합니다. 그게 바로 내가 몇 시간 전에 생각한 것입니다. HMVC 패턴을 사용하기 때문에, 모든 컨트롤러는 나의'Request' 클래스를 통해 인스턴스화됩니다. 그래서 컨트롤러의 메소드를 오토로더로 추가하고 요청이 완료되면 제거합니다. 이것은 정말 잘 작동합니다. 당신의 도움을 주셔서 감사합니다! – Frog

0

나는 응용 프로그램간에 파일 부트 스트랩에 APPLICATION_ROOT 정의를 설정하는 것이 좋습니다 것입니다. __autoload뿐만 아니라 항상 사용할 수있는 것이 유용 할 것입니다.

+0

내'Request' 클래스의 모든 요청에 ​​대해'APPLICATION_ROOT'에 대한 정의가 변경되기 때문에 그렇게 할 수 없습니다. 응용 프로그램이 다른 응용 프로그램에서 컨트롤러를로드 할 수 있고 응용 프로그램이 더 이상 올바르지 않습니다. 다른 방법을 생각해도 될까요? – Frog

관련 문제