Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/297.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 使用反射查找方法所属的类_Php_Class_Magento_Reflection - Fatal编程技术网

Php 使用反射查找方法所属的类

Php 使用反射查找方法所属的类,php,class,magento,reflection,Php,Class,Magento,Reflection,我在Magento工作,但这更像是一个普通的PHP问题。情况是,在Magento中,有一些类扩展了扩展类的类,这些类扩展了扩展类的类。我希望能够快速找到哪个类实际包含某个方法的定义和/或该方法是否实际包含 例如,如果我深入到扩展其他类的类的10个级别,并且这10个类中有4个类有一个名为getHtml的方法,那么我想知道在调用$this->getHtml()时,实际调用的是哪一个方法。我还想知道getHtml是否真的是一种神奇的方法 如何使用PHP反射类或任何其他编程方式实现这一点?(下面是未经测

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

例如,如果我深入到扩展其他类的类的10个级别,并且这10个类中有4个类有一个名为
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');
}