我在Magento工作,但这更像是一个普通的PHP问题。情况是在Magento中,有些类扩展了扩展类的类。我希望能够快速找到哪个类实际包含方法的定义和/或该方法实际上是magic。
例如,如果我在扩展其他类的类中深入10级,并且这10个类中的4个具有名为getHtml
的方法,我希望能够找出这些方法中的哪一个实际上是在我拨打$this->getHtml()
时被呼叫。我还希望能够判断getHtml
是否真的是一种神奇的方法。
如何使用PHP Reflection Class或任何其他编程方法执行此操作?
答案 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_Abstract
或Mage_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');
}