【问题标题】:PHPdoc - defining object properties for an object of stdClassPHPdoc - 为 stdClass 的对象定义对象属性
【发布时间】:2012-09-08 06:34:45
【问题描述】:

我试图弄清楚是否可以使用 PHPdoc 来定义由函数或对象方法返回的对象属性。

假设我有以下课程:

class SomeClass {
    public function staffDetails($id){

        $object = new stdClass();
        $object->type = "person";
        $object->name = "dave";
        $object->age = "46";        

        return $object;
    }
}

现在,定义输入参数很容易。

 /**
 * Get Staff Member Details
 * 
 * @param   string  $id    staff id number
 * 
 * @return  object
 */

class SomeClass {
    public function staffDetails($id){
        $object = new stdClass();
        $object->type = "person";
        $object->name = "dave";
        $object->age = "46";        

        return $object;
    }
}

问题是定义相关方法返回的输出对象(stdClass)的属性是否有类似的东西。这样其他程序员就不必打开这个类并手动查看方法来查看返回对象返回的内容是什么?

【问题讨论】:

  • 你为什么不拥有一个带有 type、name 和 age 属性的 StaffDetails 类呢?然后你可以使用@param StaffDetails
  • 如果您不想为 stdClass 创建具体类型,您仍然可以编写 @return \stdClass holding type, name and age 或在 Doc Block 的详细说明中进行解释。至少它当时被记录在案。不过,这不会让您的 IDE 神奇地知道属性。
  • 否 - 我不希望 IDE 知道属性。我只是希望他们有很好的记录。我实际使用的对象中有大约 40 个变量,所以我真的很想知道这是否是一种在表格中很好地布置它们的方法,就像输入参数出现一样。否则,如果只是使用冗长的描述,它会变得混乱且难以阅读。
  • @l_t 好吧,您总是可以在 DocBlock 的长描述中记录它们。但是一个有 40 个变量的对象对于一个知道太多的对象来说是一个很好的指标。您可以将该对象拆分为 4 到 10 个单独的对象。寻找可以分组的属性。将它们提取到自己的类中。然后将主类与该类关联,这样您最终会得到一个很好的专用对象图。
  • @Gordon 谢谢- 有问题的方法是许多不同类的分组。我这样做是为了让前端开发人员只需调用一个类方法并返回一个对象,其中包含该页面所需的所有已清理/预处理的数据(在本例中为产品数据)。这通常不是一个好主意吗?

标签: php phpdoc code-documentation


【解决方案1】:

这里是 4 年后,似乎仍然没有一种方法来注释您的问题中最初描述的 stdClass 对象的属性。

集合已在 PSR-5 中提出,但似乎已被否决:https://github.com/php-fig/fig-standards/blob/211063eed7f4d9b4514b728d7b1810d9b3379dd1/proposed/phpdoc.md#collections

似乎只有两个选项可用:

选项 1:

创建一个代表您的数据对象的普通类并注释属性。

class MyData
{
    /**
     * This is the name attribute.
     * @var string
     */
    public $name;

    /**
     * This is the age attribute.
     * @var integer
     */
    public $age;
}

选项 2:

按照Gordon 的建议创建一个通用的Struct 类型类并将其扩展为您的数据对象,使用@property 注释来定义可以使用__get__set 访问的通用值。

class Struct
{
    /**
     * Private internal struct attributes
     * @var array
     */
    private $attributes = [];

    /**
     * Set a value
     * @param string $key
     * @param mixed $value
     */
    public function __set($key, $value)
    {
        $this->attributes[$key] = $value;
    }

    /**
     * Get a value
     * @param string $key
     * @return mixed
     */
    public function __get($key)
    {
        return isset($this->attributes[$key]) ? $this->attributes[$key] : null;
    }

    /**
     * Check if a key is set
     * @param string $key
     * @return boolean
     */
    public function __isset($key)
    {
        return isset($this->attributes[$key]) ? true : false;
    }
}

/**
 * @property string $name
 * @property integer $age
 */
class MyData extends Struct
{
    // Can optionally add data mutators or utility methods here
}

【讨论】:

  • 如果您选择选项 1,您可以在 IDE 扫描但被项目忽略的文件中声明该类。声明该方法返回StaffMember,但在实现中继续使用stdClass
  • 如何让一个文件被 IDE 扫描但被 NetBeans 项目忽略?
  • 这是一个老问题——我建议问一个新问题。
【解决方案2】:

您只有两种方法来记录结果类的结构。

1.可以在注释文本中描述结构。例如:

class SomeClass 
{
    /**
     * Getting staff detail.
     * Result object has following structure:
     * <code>
     * $type - person type
     * $name - person name
     * $age - person age
     * </code>
     * @param string $id staff id number
     *
     * @return stdClass
     *
     */
    public function staffDetails($id){
        $object = new stdClass();
        $object->type = "person";
        $object->name = "dave";
        $object->age = "46";
        return $object;
    }
}

2.可以创建一个继承stdClass的数据类型,并且它会有一个结果对象的注解。例如:

/**
 * @property string $type Person type
 * @property string $name Person name
 * @property integer $age Person age
 */
class DTO extends stdClass
{}

并在你的其他课程中使用它

class SomeClass {

    /**
     * Getting staff detail.
     *
     * @param string $id staff id number
     *
     * @return DTO
     *
     */
    public function staffDetails($id){

        $object = new DTO();
        $object->type = "person";
        $object->name = "dave";
        $object->age = "46";

        return $object;
    }
}

在我看来,这种方式比文本注释中的描述要好,因为它使代码更明显

【讨论】:

  • 选项 1 - 不会帮助您的 IDE 使用它,选项 2 - 会破坏 PSR 约定
  • @YevgeniyAfanasyev 是的,选项 1 对 IDE 没有帮助,它只能帮助将使用您的代码的开发人员 - 他/她至少会看到结构。选项 2 - PSR 是什么意思?
  • PSR4 spec 说: >终止类名对应一个以.php结尾的文件名。文件名必须与终止类名的大小写匹配。
  • @YevgeniyAfanasyev 它与 PSR-4 无关,因为我的答案中没有任何文件。这只是一个简单的代码示例。
  • 您好像建议将 2 个类放在一个文件中
【解决方案3】:

如果你使用的是 PHP 7,你可以定义匿名类。

class SomeClass {
    public function staffDetails($id){
        $object = (new class() extends stdClass {
                public /** @var string  */ $type;
                public /** @var string  */ $name;
                public /** @var int     */ $age;
            });

        $object->type = "person";
        $object->name = "dave";
        $object->age  = 46;        

        return $object;
    }
}

它适用于我的 IDE(在 NetBeans 中测试)

【讨论】:

    【解决方案4】:

    例如使用json_decode,使用自己的类而不是stdClass 更难,但在我的情况下,我只是创建了带有类定义的虚拟文件,实际上没有加载,我将自己的类添加为@987654323 @(适用于 vscode 上的 intelephense)。

    PHPdocObjects.php

    /**
     * class only for PHPdoc (do not include)
     */
    class Member {
        /** @var string */
        public $type;
        /** @var string */
        public $name;
        /** @var string */
        public $age;
    }
    
    /**
     * Other format
     *
     * @property string $type;
     * @property string $name;
     * @property string $age;
     */
    class MemberAlt {}
    

    SomeClass.php

     /**
     * Get Staff Member Details
     * 
     * @param   string  $id    staff id number
     * 
     * @return  Member  I'm in fact stdClass
     */
    
    class SomeClass {
        public function staffDetails($id){
            $object = json_decode('{"type":"person","name":"dave","age":"46"}');
            return $object;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-13
      • 2013-10-17
      • 2012-11-25
      • 1970-01-01
      • 2011-02-08
      • 2014-07-04
      • 2015-12-03
      • 1970-01-01
      相关资源
      最近更新 更多