我在 Magento 工作,但这更像是一个一般的 PHP 问题。情况是在 Magento 中,有些类扩展类,类扩展类。我希望能够快速找到哪个类实际包含方法的定义和/或该方法是否实际上是 magic .
例如,如果我深入 10 个类来扩展其他类,并且这 10 个类中有 4 个有一个名为 getHtml
的方法,我希望能够找出其中的哪一个当我调用 $this->getHtml()
时,方法实际上被调用了。我还想知道 getHtml
是否真的是一个神奇的方法。
我如何使用 PHP 反射类或任何其他编程方式来做到这一点?
最佳答案
(下面未经测试的代码——如果您发现任何错误,我将不胜感激在评论中进行更新)
您使用反射 API 所能做的最好的事情就是在层次结构中找到未定义方法的类。 ReflectionClass
的 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
或 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
方法。以上将返回
array (size=2)
0 => string 'Mage_Catalog_Model_Abstract' (length=27)
1 => string 'Varien_Object' (length=13)
因为 setData
在 Mage_Catalog_Model_Abstract
类和 Varien_Object
类中都有定义。您应该能够修改这些函数以满足您自己的需要。祝你好运!
关于php - 使用反射查找某个方法所属的类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22873403/