Php 使用反射查找方法所属的类
我在Magento工作,但这更像是一个普通的PHP问题。情况是,在Magento中,有一些类扩展了扩展类的类,这些类扩展了扩展类的类。我希望能够快速找到哪个类实际包含某个方法的定义和/或该方法是否实际包含 例如,如果我深入到扩展其他类的类的10个级别,并且这10个类中有4个类有一个名为Php 使用反射查找方法所属的类,php,class,magento,reflection,Php,Class,Magento,Reflection,我在Magento工作,但这更像是一个普通的PHP问题。情况是,在Magento中,有一些类扩展了扩展类的类,这些类扩展了扩展类的类。我希望能够快速找到哪个类实际包含某个方法的定义和/或该方法是否实际包含 例如,如果我深入到扩展其他类的类的10个级别,并且这10个类中有4个类有一个名为getHtml的方法,那么我想知道在调用$this->getHtml()时,实际调用的是哪一个方法。我还想知道getHtml是否真的是一种神奇的方法 如何使用PHP反射类或任何其他编程方式实现这一点?(下面是未经测
getHtml
的方法,那么我想知道在调用$this->getHtml()
时,实际调用的是哪一个方法。我还想知道getHtml
是否真的是一种神奇的方法
如何使用PHP反射类或任何其他编程方式实现这一点?(下面是未经测试的代码-如果您发现任何bug,我希望在注释中进行更新)
使用反射API所能做的最好的事情就是在层次结构中找到方法未定义的类。ReflectionClass
的hasMethod
功能将考虑父类-更好的名称可能是aClassInTheHierarchyHasThisMethod
。考虑这个(快速顶部我的头)内联函数< /p>
$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\u对象
没有定义方法load
,这意味着它首先出现在Mage\u Core\u Model\u Abstract
中。但是,您不知道在Mage\u Catalog\u Model\u Abstract
或Mage\u Catalog\u Model\u Product
中是否也有定义。反射API无法实现这一点
使用token\u get\u 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
方法。以上内容将返回
array (size=2)
0 => string 'Mage_Catalog_Model_Abstract' (length=27)
1 => string 'Varien_Object' (length=13)
因为setData
是在Mage\u Catalog\u Model\u Abstract
类和Varien\u对象
类中定义的。您应该能够修改这些函数以满足自己的需要。祝你好运
在这10个类中,有4个类有一个名为getHtml
的方法,我希望能够在调用$this->getHtml()
时找出实际调用的是哪一个方法
您可能正在寻找的方法是告诉方法名称及其响应的方法。类名已经存在
如果找不到具体的方法名称,则需要查找\uu类
以下是对公共方法执行此操作的示例函数:
演示:Alan,我发现自己一直在你的网站上!在这里得到你的直接帮助也很酷。我会尽快进行测试,然后回复您。另一种编程方式是
grep'加载('app-rsn
@anton是一个很好的开始,但是有200多个类使用了load
方法。@TylerV如何知道哪些类与他正在使用的层次结构相关?他可以从指定或缩小grep路径开始。grep并非在每种情况下都是金色的,并且使用更具体的方法名可以提供更好的结果。这是一个更轻松的选择例如,在我最终在一个简单的调试模块中将其转换为一个帮助器类之后,您是否需要更高级的日志记录来了解自己的情况。非常好!谢谢@AlanStorm
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');
}