【问题标题】:php: get variable type hint using reflectionphp:使用反射获取变量类型提示
【发布时间】:2011-09-09 03:56:00
【问题描述】:
class Expense {

    /**
     * @var int
     */
    private $id;
}

我想在我的类中获取一个变量的类型提示,使用反射,因为默认值为 null。

【问题讨论】:

    标签: php class reflection types


    【解决方案1】:

    试试:

    <?php
    class Expense {
    
        /**
         * @var int
         */
        private $id;
    }
    
    $refClass = new ReflectionClass('Expense');
    foreach ($refClass->getProperties() as $refProperty) {
        if (preg_match('/@var\s+([^\s]+)/', $refProperty->getDocComment(), $matches)) {
            list(, $type) = $matches;
            var_dump($type);
        }
    }
    

    输出

    string(3) "int"
    

    【讨论】:

      【解决方案2】:

      获取完整的文档块:

      $reflection = new ReflectionProperty('Expense', 'id');
      
      $doc = $reflection->getDocComment();
      

      【讨论】:

        【解决方案3】:

        一点警告 - PHP 加速器和一些库本身(即 symfony 核心)剥离 cmets,通常在 运行时。

        【讨论】:

        • 确实,这就是我提出使用反射的解决方案的原因
        • 嗯,它可能在过去 8 年中发生了变化,没有跟上 PHP 的更新。
        • Unity3D 的乐趣? - 当然看起来很棒:-)
        【解决方案4】:

        如果 PHPDoc cmets 被证明丢失或不可靠,您可以键入提示类的所有属性只要它们具有匹配的 getter

        public function getClassPropertiesType(string $className): array {
            $reflectionClass = new \ReflectionClass($className);
        
            $reflectionProperties = $reflectionClass->getProperties();
            $properties = [];
            foreach ($reflectionProperties as $reflectionProperty) {
                $properties[] = $reflectionProperty->getName();
            }
        
            $methods = $reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC);
            $results = [];
        
            foreach ($properties as $property) {
                foreach ($methods as $method) {
                    // get only methods that have 0 parameter and start with 'get'
                    if ($method->getNumberOfParameters() === 0 && 
                          strpos($method->getName(),'get') !== false && 
                          stripos($method->getName(), $property) !== false) {
        
                        $results[$property] = (string)$method->getReturnType();
                    }
                }
            }
        
            return $results;
        }
        

        从逻辑上讲,类的每个属性应该只有一个 getter。

        如果我转储某个类的属性:

          0 => "id"
          1 => "email"
          2 => "password"
          3 => "firstName"
          4 => "lastName"
          5 => "gender"
          6 => "position"
          7 => "isActive"
          9 => "dateEmployedFrom"
          10 => "dateEmployedTo"
          11 => "dateOfBirth"
          12 => "ssn"
          13 => "mobilePhone"
          14 => "homePhone"
          15 => "address"
          16 => "zipCode"
          17 => "city"
          18 => "country"
        

        这就是你得到的:

          "id" => "int"
          "email" => "string"
          "password" => "string"
          "firstName" => "string"
          "lastName" => "string"
          "gender" => "bool"
          "position" => "string"
          "isActive" => "bool"
          "dateEmployedFrom" => "DateTimeInterface"
          "dateEmployedTo" => "DateTimeInterface"
          "dateOfBirth" => "DateTimeInterface"
          "ssn" => "string"
          "mobilePhone" => "string"
          "homePhone" => "string"
          "address" => "string"
          "zipCode" => "string"
          "city" => "string"
          "country" => "string"
        

        限制 + 解决方法

        如果一个属性没有任何getter,你可以开始寻找setter(或以'add'、'is'、'remove'开头的方法),只要方法的参数是类型提示的时间>。 您还可以在搜索中包含私有属性 $methods = $reflectionClass-&gt;getMethods(); // no filter

        我建议在返回之前像这样扩展:

                $missingProperties = array_diff_key(array_flip($properties), $results);
        
                if (!empty($missingProperties)) { // some properties are missing
        
                    foreach ($missingProperties as $missingProperty => $val) {
                        // get only methods that have 1 parameter and start with 'set'
                        if ($method->getNumberOfParameters() === 1 && strpos($method->getName(), 'set') !== false) { 
                            $parameters = $method->getParameters();
        
                            // if not already in results, and parameter is required 
                            // and is a class property
                            if(!array_key_exists($parameters[0]->getName(), $results) &&
                                        !$parameters[0]->isOptional() && 
                                        in_array($parameters[0]->getName(), $properties, true)) {
        
                                $string = $parameters[0]->__toString();
        
                                $string = substr($string, strlen('Parameter #0 [ <required> '));
                                $pos = strpos($string, ' '); // get first space after type
                                $string = substr($string, 0, $pos); // get type
        
                                $results[$parameters[0]->getName()] = $string;
                            }
                        }
                    }
                }
        

        当然,这不是 100% 防弹的,但希望它会有所帮助。 :-)

        最后:PHP 7.4 引入ReflectionParameter::getType 所以,你可以放弃上面的字符串操作,只写:

                        $type = $parameters[0]->getType();
                        $results[$parameters[0]->getName()] = $type->__toString();
        

        【讨论】:

          【解决方案5】:

          对于 PHP 7.4

          $reflection = new \ReflectionProperty('className', 'propertyName');
          echo $reflection->getType()->getName();
          

          【讨论】:

            【解决方案6】:

            您可以使用ReflectionDocBlock

            安装

            composer require phpdocumentor/reflection-docblock
            

            用法:

            $factory  = \phpDocumentor\Reflection\DocBlockFactory::createInstance();
            
            $reflectionClass = new ReflectionClass(MyClass::class);
            $property = $reflectionClass->getProperty('foo');
            
            $docBlock = $factory->create($property->getDocComment());
            
            //it returns an array, as a property might declare many types
            //for example @var int|string|null
            $types = $docBlock->getTagsByName('var')[0]->getType()
            

            参见ReflectionClassReflectionProperty的参考

            【讨论】:

              【解决方案7】:

              在 PHP7.4 中

                  public function getKeysAndTypes(): array
                  {
                      $return = [];
                      $reflectionClass = new \ReflectionClass(static::class);
                      foreach ($reflectionClass->getProperties() as $reflectionProperty) {
                          if ($reflectionProperty->isPublic()) {
                              $return[$reflectionProperty->getName()] = $reflectionProperty->getType()->getName();
                          }
                      }
                      return $return;
                  }
              
              

              【讨论】:

                猜你喜欢
                • 2012-01-28
                • 2012-04-03
                • 1970-01-01
                • 1970-01-01
                • 2019-03-21
                • 2018-06-05
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多