2014-04-04 2 views
4

Magento에서 일하고 있습니다. 그러나 이것은 일반적인 PHP 관련 질문입니다. 상황에 따라 Magento에는 클래스를 확장하는 클래스가 확장되어 클래스를 확장하는 클래스가 있습니다. 나는 어떤 클래스가 실제로 메소드의 정의를 포함하고 있는지 그리고/또는 그 메소드가 실제로 magic인지를 빨리 알 수 있기를 원한다.Reflection을 사용하여 메소드가 속한 클래스를 찾으십시오.

예를 들어, 다른 클래스를 확장하는 클래스가 10 레벨 깊숙이 있고 그 중 10 클래스에 getHtml이라는 메서드가있는 경우 해당 메서드 중 실제로 어느 것이 호출되는지 확인할 수 있기를 바랍니다. 전화 : $this->getHtml(). 나는 또한 getHtml이 실제로 마술 방법인지 말할 수 있기를 바랍니다.

어떻게하면 PHP 리플렉션 클래스 또는 다른 프로그래밍 방식으로이 작업을 수행 할 수 있습니까?

답변

10

- 당신은 리플렉션 API와 함께 할 수있을 것이다 가장 계층 구조의 클래스를 찾을 수있다

(아래 테스트되지 않은 코드가 당신이 어떤 버그를 발견하면 내가 코멘트에 업데이 트를 감사하겠습니다) 어디 방법은 이 아니며이 정의되어 있습니다. ReflectionClasshasMethod 기능은 상위 클래스를 고려합니다. 더 좋은 이름은 aClassInTheHierarchyHasThisMethod 일 수 있습니다. 이 (빠른 최고 내 머리) 인라인 함수

$getClassesWithMethod = function($classOrObject, $method, $return=false) use(&$getClassesWithMethod) 
    { 
     $return = $return ? $return : new ArrayObject; 
     $r = new ReflectionClass($classOrObject); 
     if($r->hasMethod($method)) 
     { 
      $return['has ' . $method . ' method'][] = $r->getName(); 
     } 
     else 
     { 
      $return['no '. $method . ' method'][] = $r->getName(); 
     } 

     $parent = $r->getParentClass(); 
     if($parent) 
     { 
      $getClassesWithMethod($parent->getName(), $method, $return); 
     } 
     return $return; 
    }; 

    $product = Mage::getModel('catalog/product'); 

    $classesWithMethod = $getClassesWithMethod($product, 'load'); 
    var_dump((array)$classesWithMethod); 

실행 위를 고려, 당신은

array (size=2) 
    'has load method' => 
    array (size=4) 
     0 => string 'Mage_Catalog_Model_Product' (length=26) 
     1 => string 'Mage_Catalog_Model_Abstract' (length=27) 
     2 => string 'Mage_Core_Model_Abstract' (length=24) 
    'no load method' => 
    array (size=1) 
     0 => string 'Varien_Object' (length=13) 

그래서 당신이 Varien_Object이 방법 load 의미하는 정의가없는 알거야 그것은 Mage_Core_Model_Abstract에 처음 나타납니다. 그러나 Mage_Catalog_Model_Abstract 또는 Mage_Catalog_Model_Product에 정의가 있는지 알 수 없습니다. Reflection API는 당신에게 이것을주지 않을 것이다.

무엇 수 있습니다token_get_all 방법을 사용하여 이것을 얻을. 이 방법은 PHP 파일을 PHP/Zend 토큰의 구성 요소로 분해 할 수 있습니다. 일단 그렇게하면 특정 클래스 파일에서 메소드/함수 정의를 식별하는 작은 파서를 PHP에 작성할 수 있습니다. 이를 사용하여 반복적으로 계층을 검사 할 수 있습니다. 인라인 함수.

$getClassesWithConcreteDefinition = function($classOrObject,$method,$return=false) use(&$getClassesWithConcreteDefinition) 
    { 
     $return = $return ? $return : new ArrayObject; 
     $r = new ReflectionClass($classOrObject); 
     $tokens = token_get_all(file_get_contents($r->getFilename())); 

     $is_function_context = false; 
     foreach($tokens as $token) 
     { 
      if(!is_array($token)){continue;}     
      $token['name'] = token_name($token[0]); 
      if($token['name'] == 'T_WHITESPACE'){ continue; } 

      if($token['name'] == 'T_FUNCTION') 
      { 
       $is_function_context = true; 
       continue; 
      } 

      if($is_function_context) 
      { 
       if($token[1] == $method) 
       { 
        $return[] = $r->getName(); 
       } 
       $is_function_context = false; 
       continue; 
      } 
     } 

     $parent = $r->getParentClass(); 
     if($parent) 
     { 
      $getClassesWithConcreteDefinition($parent->getName(),$method,$return); 
     } 

     return $return; 
    }; 

    $product = Mage::getModel('catalog/product');   

    $hasActualDefinition = $getClassesWithConcreteDefinition($product, 'setData'); 
    var_dump((array)$hasActualDefinition); 

여기서 우리는 setData 메소드를 검사합니다. setDataMage_Catalog_Model_Abstract 클래스와 Varien_Object 클래스 모두에 정의되어 있기 때문에 위는

array (size=2) 
    0 => string 'Mage_Catalog_Model_Abstract' (length=27) 
    1 => string 'Varien_Object' (length=13) 

를 반환합니다. 자신의 필요에 맞게이 기능을 수정할 수 있어야합니다. 행운을 빕니다! 그 10 종류의

+0

앨런, 나는 당신의 웹 사이트에 모든 시간 자신을 찾을 수

다음은 공공 방법에 대해이 작업을 수행하는 예 기능입니다! 여기에 직접 도움을 받으시는 것도 좋습니다. 나는 가능한 한 빨리 이것을 시험해보고 다시 너에게 다가 가겠다. –

+0

다른 프로그래밍 방식 'grep 'load ('app -rsn' –

+0

@AntonS 좋은 시작이지만'load' 메소드로 200 개가 넘는 클래스가 있습니다 @TylerV는 그가 작업하고있는 계층 구조와 관련된 것들을 어떻게 알 수 있습니까? ? –

1

4 내가 $this->getHtml()를 호출 할 때 그 방법 중 하나가 실제로 호출되고있는 찾을 수 있도록하려면, 방법은 getHtml라고합니다.

아마도 당신이 찾고있는 방법은 ReflectionClass::getMethods()이며 메소드 이름과 해당 문자를 알려줍니다. 이미 클래스 이름.

구체적인 method-name을 찾을 수없는 경우 __class을 찾아야합니다.

function traverseParentsForMethod($objOrClassname, $methodName) { 
    $refl = new ReflectionClass($objOrClassname); 

    $methods = $refl->getMethods(ReflectionMethod::IS_PUBLIC); 
    foreach ($methods as $method) { 
     if ($method->getName() === $methodName) { 
      return $method; 
     } 
    } 

    if ($methodName === '__call') { 
     return null; 
    } 

    return traverseParentsForMethod($objOrClassname, '__call'); 
} 

데모 : https://eval.in/132292

관련 문제