【问题标题】:PHP Reflection - Get Method Parameter Type As StringPHP 反射 - 获取方法参数类型为字符串
【发布时间】:2010-12-22 21:22:23
【问题描述】:

我正在尝试使用 PHP 反射根据控制器方法中的参数类型自动动态加载模型的类文件。这是一个示例控制器方法。

<?php

class ExampleController
{
    public function PostMaterial(SteelSlugModel $model)
    {
        //etc...
    }
}

这是我目前所拥有的。

//Target the first parameter, as an example
$param = new ReflectionParameter(array('ExampleController', 'PostMaterial'), 0);

//Echo the type of the parameter
echo $param->getClass()->name;

这可行,并且输出将是“SteelSlugModel”,正如预期的那样。但是,模型的类文件可能尚未加载,并且使用 getClass() 需要定义类 - 我这样做的部分原因是自动加载控制器操作可能需要的任何模型.

有没有办法不用先加载类文件就可以得到参数类型的名字?

【问题讨论】:

  • 什么是$p?你的意思是$param
  • 除非 Reflection 类在其文档中缺少重要的信息,否则我认为如果不加载该类就无法获得提示类型。
  • @simshaun:不。需要加载类,否则getClass 会抛出ReflectionException
  • @netcoder,我知道 getClass。我基本上是在说“除非有另一种方法可以获取我不知道或在文档中找不到的提示类型”
  • @Rafe - 是的,$p 应该是 $param。已在代码中修复。

标签: php reflection


【解决方案1】:

我想这就是你要找的东西:

class MyClass {

    function __construct(AnotherClass $requiredParameter, YetAnotherClass $optionalParameter = null) {
    }

}

$reflector = new ReflectionClass("MyClass");

foreach ($reflector->getConstructor()->getParameters() as $param) {
    // param name
    $param->name;

    // param type hint (or null, if not specified).
    $param->getClass()->name;

    // finds out if the param is required or optional
    $param->isOptional();
}

【讨论】:

  • 使用当前反射 API 这是最好的解决方案,应该是公认的答案。
  • getClass() 在方法签名包含“字符串”或“数组”等类型提示时会导致错误。在 PHP 上无法检测到类型“字符串”
【解决方案2】:

我认为唯一的方法是export 并操作结果字符串:

$refParam = new ReflectionParameter(array('Foo', 'Bar'), 0);

$export = ReflectionParameter::export(
   array(
      $refParam->getDeclaringClass()->name, 
      $refParam->getDeclaringFunction()->name
   ), 
   $refParam->name, 
   true
);

$type = preg_replace('/.*?(\w+)\s+\$'.$refParam->name.'.*/', '\\1', $export);
echo $type;

【讨论】:

  • 这行得通,虽然我真的希望我可以避免必须解析一个字符串来做到这一点。干得好。
  • 这仍然是唯一的方法吗?不得不依赖导出方法的非标准输出格式是粗略的!
【解决方案3】:

您可以使用 Zend Framework 2。

$method_reflection = new \Zend\Code\Reflection\MethodReflection( 'class', 'method' );

foreach( $method_reflection->getParameters() as $reflection_parameter )
{
  $type = $reflection_parameter->getType();
}

【讨论】:

  • 函数getType不再存在,现在称为getClass
【解决方案4】:

getType 方法可以从 PHP 7.0 开始使用。

class Foo {}
class Bar {}

class MyClass
{
    public function baz(Foo $foo, Bar $bar) {}
}

$class = new ReflectionClass('MyClass');
$method = $class->getMethod('baz');
$params = $method->getParameters();

var_dump(
    'Foo' === (string) $params[0]->getType()
);

【讨论】:

    【解决方案5】:

    我遇到了类似的问题,在未加载类时检查反射参数上的 getClass。我制作了一个包装函数来从示例 netcoder 中获取类名。问题是 netcoder 代码不管是数组还是类都不起作用 -> function($test) {} 它会返回反射参数的字符串方法。

    在我解决它的方式下面,我使用 try catch 因为我的代码在某些时候需要类。因此,如果我下次请求它,请让课程正常工作并且不会引发异常。

    /**
     * Because it could be that reflection parameter ->getClass() will try to load an class that isnt included yet
     * It could thrown an Exception, the way to find out what the class name is by parsing the reflection parameter
     * God knows why they didn't add getClassName() on reflection parameter.
     * @param ReflectionParameter $reflectionParameter
     * @return string Class Name
     */
    public function ResolveParameterClassName(ReflectionParameter $reflectionParameter)
    {
        $className = null;
    
        try
        {
                     // first try it on the normal way if the class is loaded then everything should go ok
            $className = $reflectionParameter->getClass()->name;
    
        }
        // if the class isnt loaded it throws an exception and try to resolve it the ugly way
        catch (Exception $exception)
        {
            if ($reflectionParameter->isArray())
            {
                return null;
            }
    
            $reflectionString = $reflectionParameter->__toString();
            $searchPattern = '/^Parameter \#' . $reflectionParameter->getPosition() . ' \[ \<required\> ([A-Za-z]+) \$' . $reflectionParameter->getName() . ' \]$/';
    
            $matchResult = preg_match($searchPattern, $reflectionString, $matches);
    
            if (!$matchResult)
            {
                return null;
            }
    
            $className = array_pop($matches);
        }
    
        return $className;
    }
    

    【讨论】:

    【解决方案6】:

    这是一个比that answer 更好的正则表达式。即使参数是可选的,它也会起作用。

    preg_match('~>\s+([a-z]+)\s+~', (string)$ReflectionParameter, $result);
    $type = $result[1];
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-05
      相关资源
      最近更新 更多