使用Reflection查找方法所属的类

时间:2014-04-04 21:33:38

标签: php class magento reflection

我在Magento工作,但这更像是一个普通的PHP问题。情况是在Magento中,有些类扩展了扩展类的类。我希望能够快速找到哪个类实际包含方法的定义和/或该方法实际上是magic

例如,如果我在扩展其他类的类中深入10级,并且这10个类中的4个具有名为getHtml的方法,我希望能够找出这些方法中的哪一个实际上是在我拨打$this->getHtml()时被呼叫。我还希望能够判断getHtml是否真的是一种神奇的方法。

如何使用PHP Reflection Class或任何其他编程方法执行此操作?

2 个答案:

答案 0 :(得分:10)

(下面未经测试的代码 - 如果您发现任何错误,我会感谢评论中的更新)

您可以使用Reflection API做的最好的事情是在层次结构中找到方法定义的类。 ReflectionClass的{​​{1}}功能会考虑父类 - 更好的名称可能是hasMethod。考虑这个(快速的我的头部)内联函数

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_AbstractMage_Catalog_Model_Abstract中是否还有定义。 Reflection API不会让你这么做。

可以使用Mage_Catalog_Model_Product方法获取此功能。这个方法可以将PHP文件分解为它的组件PHP / Zend标记。完成后,您可以在PHP中编写一个小解析器,用于标识特定类文件中的方法/函数定义。您可以使用它来递归检查层次结构。同样,内联函数。

token_get_all

我们正在检查 $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

因为array (size=2) 0 => string 'Mage_Catalog_Model_Abstract' (length=27) 1 => string 'Varien_Object' (length=13) 类和setData类中都定义了Mage_Catalog_Model_Abstract。您应该能够修改这些功能以满足您自己的需要。祝你好运!

答案 1 :(得分:1)

  

这10个类中有4个有一个名为getHtml的方法,我希望能够在调用$this->getHtml()时找出实际调用这些方法中的哪一个。

您可能正在寻找的方法是ReflectionClass::getMethods(),它告诉方法名称及其响应。 classname已经。

如果找不到具体的方法名称,则需要查找__class

以下是为 public 方法执行此操作的示例函数:

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