php 在 PHPDoc 中记录数组选项的最佳方式?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15414103/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 09:11:36  来源:igfitidea点击:

Best way to document Array options in PHPDoc?

phpcakephpphpdoc

提问by Reactgular

I'm struggling to write readable and easy to understand documentation that describes the multi-tree structure for Array options that are passed to a function.

我正在努力编写可读且易于理解的文档,这些文档描述了传递给函数的数组选项的多树结构。

Here is an example array structure.

这是一个示例数组结构。

$arr = [
   'fields' => [
       'title' => [
           'name'     => 'Document.title',
           'format'   => 'string',
           'readonly' => true
       ]
   ]
];

There are many possible options for the above array, but this is used as a parameter to a function that understands that structure.

上述数组有许多可能的选项,但这被用作理解该结构的函数的参数。

function doSomething(array $arr) { ... }

I'd like to document how the array should be structured in PHPDoc, but I'm not sure what the correct approach is.

我想记录如何在 PHPDoc 中构建数组,但我不确定正确的方法是什么。

Here is what I have now.

这是我现在所拥有的。

/**
 * Holds configuration settings for each field in a model.
 * Defining the field options
 *
 * array['fields'] array Defines the feilds to be shown by scaffolding.
 * array['fields'][fieldName] array Defines the options for a field, or just enables the field if array is not applied.
 * array['fields'][fieldName]['name'] string Overrides the field name (default is the array key)
 * array['fields'][fieldName]['model'] string (optional) Overrides the model if the field is a belongsTo assoicated value.
 * array['fields'][fieldName]['width'] string Defines the width of the field for paginate views. Examples are "100px" or "auto"
 * array['fields'][fieldName]['align'] string Alignment types for paginate views (left, right, center)
 * array['fields'][fieldName]['format'] string Formatting options for paginate fields. Options include ('currency','nice','niceShort','timeAgoInWords' or a valid Date() format)
 * array['fields'][fieldName]['title'] string Changes the field name shown in views.
 * array['fields'][fieldName]['desc'] string The description shown in edit/create views.
 * array['fields'][fieldName]['readonly'] boolean True prevents users from changing the value in edit/create forms.
 * array['fields'][fieldName]['type'] string Defines the input type used by the Form helper (example 'password')
 * array['fields'][fieldName]['options'] array Defines a list of string options for drop down lists.
 * array['fields'][fieldName]['editor'] boolean If set to True will show a WYSIWYG editor for this field.
 * array['fields'][fieldName]['default'] string The default value for create forms.
 *
 * @param array $arr (See above)
 * @return Object A new editor object.
 **/

My problem is that when the HTML document is generated, it's not formatted very nicely. Additionally, I'm not sure the above is clearly explains the array structure.

我的问题是当生成 HTML 文档时,它的格式不是很好。另外,我不确定上面是否清楚地解释了数组结构。

Is there an alternative approach?

有替代方法吗?

采纳答案by aleation

Just adding some tabulation will make it look good and easy to understand

只需添加一些表格就可以使它看起来很好且易于理解

/**
 * Holds configuration settings for each field in a model.
 * Defining the field options
 *
 * array['fields']              array Defines the fields to be shown by scaffolding.
 *          [fieldName]         array Defines the options for a field, or just enables the field if array is not applied.
 *              ['name']        string Overrides the field name (default is the array key)
 *              ['model']       string (optional) Overrides the model if the field is a belongsTo associated value.
 *              ['width']       string Defines the width of the field for paginate views. Examples are "100px" or "auto"
 *              ['align']       string Alignment types for paginate views (left, right, center)
 *              ['format']      string Formatting options for paginate fields. Options include ('currency','nice','niceShort','timeAgoInWords' or a valid Date() format)
 *              ['title']       string Changes the field name shown in views.
 *              ['desc']        string The description shown in edit/create views.
 *              ['readonly']    boolean True prevents users from changing the value in edit/create forms.
 *              ['type']        string Defines the input type used by the Form helper (example 'password')
 *              ['options']     array Defines a list of string options for drop down lists.
 *              ['editor']      boolean If set to True will show a WYSIWYG editor for this field.
 *              ['default']     string The default value for create forms.
 *
 * @param array $arr (See above)
 * @return Object A new editor object.
 **/

A nested list approach:

嵌套列表方法:

<ul>
    <li>
        array['fields'] array Defines the fields to be shown by scaffolding.
        <ul>
            <li>
                [fieldName]             array Defines the options for a field, or just enables the field if array is not applied.
                <ul>
                    <li> ['name']       <i><u>string</u></i> Overrides the field name (default is the array key) </li>
                    <li> ['model']      <i><u>string</u></i> (optional) Overrides the model if the field is a belongsTo associated value.</li>
                    <li> ['width']      <i><u>string</u></i> Defines the width of the field for paginate views. Examples are "100px" or "auto"</li>
                    <li> ['align']      <i><u>string</u></i> Alignment types for paginate views (left, right, center)</li>
                    <li> ['format']     <i><u>string</u></i> Formatting options for paginate fields. Options include ('currency','nice','niceShort','timeAgoInWords' or a valid Date() format)</li>
                    <li> ['title']      <i><u>string</u></i> Changes the field name shown in views.</li>
                    <li> ['desc']       <i><u>string</u></i> The description shown in edit/create views.</li>
                    <li> ['readonly']   <i><u>boolean</u></i> True prevents users from changing the value in edit/create forms.</li>
                    <li> ['type']       <i><u>string</u></i> Defines the input type used by the Form helper (example 'password')</li>
                    <li> ['options']    <i><u>array</u></i> Defines a list of string options for drop down lists.</li>
                    <li> ['editor']     <i><u>boolean</u></i> If set to True will show a WYSIWYG editor for this field.</li>
                    <li> ['default']    <i><u>string</u></i> The default value for create forms.</li>
                </ul>
            </li>
        </ul>
    </li>
 </ul>

Result:

结果:

  • array['fields'] array Defines the fields to be shown by scaffolding.
    • [fieldName] array Defines the options for a field, or just enables the field if array is not applied.
      • ['name'] stringOverrides the field name (default is the array key)
      • ['model'] string(optional) Overrides the model if the field is a belongsTo associated value.
      • ['width'] stringDefines the width of the field for paginate views. Examples are "100px" or "auto"
      • ['align'] stringAlignment types for paginate views (left, right, center)
      • ['format'] stringFormatting options for paginate fields. Options include ('currency','nice','niceShort','timeAgoInWords' or a valid Date() format)
      • ['title'] stringChanges the field name shown in views.
      • ['desc'] stringThe description shown in edit/create views.
      • ['readonly'] booleanTrue prevents users from changing the value in edit/create forms.
      • ['type'] stringDefines the input type used by the Form helper (example 'password')
      • ['options'] arrayDefines a list of string options for drop down lists.
      • ['editor'] booleanIf set to True will show a WYSIWYG editor for this field.
      • ['default'] stringThe default value for create forms.
  • array['fields'] array 定义脚手架显示的字段。
    • [fieldName] array 定义字段的选项,或者如果未应用 array,则仅启用该字段。
      • ['name'] string覆盖字段名称(默认为数组键)
      • ['model'] 字符串(可选)如果该字段是关联的值,则覆盖模型。
      • ['width'] string定义分页视图的字段宽度。例如“100px”或“auto”
      • ['align'] string分页视图的对齐类型(左、右、中)
      • ['format'] string分页字段的格式选项。选项包括('currency'、'nice'、'niceShort'、'timeAgoInWords' 或有效的 Date() 格式)
      • ['title'] 字符串更改视图中显示的字段名称。
      • ['desc'] string在编辑/创建视图中显示的描述。
      • ['readonly'] booleanTrue 防止用户更改编辑/创建表单中的值。
      • ['type'] string定义表单助手使用的输入类型(例如'password')
      • ['options'] array定义下拉列表的字符串选项列表。
      • ['editor'] boolean如果设置为 True 将显示此字段的 WYSIWYG 编辑器。
      • ['default'] string创建表单的默认值。

If you want it to look fancy, with a bit of Css it will make wonders! xd

如果你想让它看起来很花哨,用一点 Css 它会创造奇迹!xd

回答by siannone

A bit too late to the party but this is how I do it instead:

参加聚会有点太晚了,但我是这样做的:

/**
 * Class constructor.
 *
 * @param array $params Array containing the necessary params.
 *    $params = [
 *      'hostname'     => (string) DB hostname. Required.
 *      'databaseName' => (string) DB name. Required.
 *      'username'     => (string) DB username. Required.
 *      'password'     => (string) DB password. Required.
 *      'port'         => (int) DB port. Default: 1433.
 *      'sublevel'     => [
 *          'key' => (\stdClass) Value description.
 *      ]
 *    ]
 */
 public function __construct(array $params){}

Think it's quite clean and easy to understand what $paramsshould be.

认为它很干净,很容易理解$params应该是什么。

回答by Klesun

I wrote a plugin for phpstormthat allows specifying keys like this:

为 phpstorm编写了一个插件,允许指定这样的键:

(basically just a slightly stricter version of @siannone's format)

(基本上只是@siannone 格式的稍微严格的版本)

/**
 * @param array $arr = [
 *     'fields' => [ // Defines the feilds to be shown by scaffolding
 *         $anyKey => [
 *             'name' => 'sale', // Overrides the field name (default is the array key)
 *             'model' => 'customer', // (optional) Overrides the model if the field is a belongsTo associated value.
 *             'width' => '100px', // Defines the width of the field for paginate views. Examples are "100px" or "auto"
 *             'align' => 'center', // Alignment types for paginate views (left, right, center)
 *             'format' => 'nice', // Formatting options for paginate fields. Options include ('currency','nice','niceShort','timeAgoInWords' or a valid Date() format)
 *             'title' => 'Sale', // Changes the field name shown in views.
 *             'desc' => 'A deal another person that results in money', // The description shown in edit/create views.
 *             'readonly' => false, // True prevents users from changing the value in edit/create forms.
 *             'type' => 'password', // Defines the input type used by the Form helper
 *             'options' => ['option1', 'option2'], // Defines a list of string options for drop down lists.
 *             'editor' => false, // If set to True will show a WYSIWYG editor for this field.
 *             'default' => '', // The default value for create forms.
 *         ],
 *     ],
 * ]
 */
public static function processForm($arr)
{
    $fieldName = 'sale';
    $arr['fields'][$fieldName][''];
}

enter image description here

在此处输入图片说明

It allows to specify @returnkeys as well:

它还允许指定@return键:

/**
 * @return array [
 *     'success' => true,
 *     'formObject' => new Form,
 *     'errors' => [],
 * ]
 */
public static function processForm($arr);

enter image description here

在此处输入图片说明

回答by jjok

Can you use objects instead of arrays? That would make documentation easy.

你可以使用对象而不是数组吗?这将使文档变得容易。

class Field {

    /**
     * The name of the thing.
     * @var string
     */
    protected $name;

    protected $model;
    protected $width;
    //...

    public function getName() {...}
    public function setName() {...}
    //...
}

class FieldList implements SomeKindOfIterator {

    /**
     * Some fields.
     * @var Field[]
     */
    protected $fields = array();

    /**
     * ...
     */
    public function push(Field $field) {
         $this->fields[] = $field;
    }

    //...
}

Then you can use a type hint where the class is required.

然后,您可以在需要该类的地方使用类型提示。

/**
 * Do something.
 * @param FieldList $field_list The field.
 */
function doSomething(FieldList $field_list) {...}

回答by jk2K

Markdown Syntax for Object Notation(MSON) may be a better choice.

Markdown Syntax for Object Notation(MSON) 可能是更好的选择。

example

例子

/**
 * @param array $config
 *   + app (string, required) - app directory name
 *   + view (string, required) - view directory name
 *   + type (enum[string]) - site type
 *     + pc - PC version
 *     + wap - mobile version
 *     + other - other, default value
 *   + table_prefix (string) - database table prefix
 */

回答by CommaToast

I kinda like this better:

我更喜欢这个:

 * @param array $doc
 *          'type'=>Doc::MY_DOC_TYPE,
 *          'created'=>$now,
 *          'modified'=>$now

I just paste in the code from where it gets initialized, quick and easy.

我只是粘贴代码,从它被初始化的地方开始,快速而简单。

回答by Mark Baker

AS this is purely display rather than a directive, and should retain space formatting within the docs, I'd be inclined to go for readability with indentation rather than a wall of characters:

由于这纯粹是显示而不是指令,并且应该在文档中保留空格格式,因此我倾向于使用缩进而不是字符墙来提高可读性:

 * array['fields'] array Defines the feilds to be shown by scaffolding.
 *           [fieldName] array Defines the options for a field, or just enables
 *                             the field if array is not applied.
 *                 ['name'] string Overrides the field name (default is the
 *                                  array key)
 *                 ['model'] string (optional) Overrides the model if the field is
 *                                  a belongsTo assoicated value.
 *                 ['width'] string Defines the width of the field for paginate
 *                                  views.
 *                                  Examples are "100px" or "auto"
 *                 ['align'] string Alignment types for paginate views (left, 
 *                                 right, center)
 *                 ['format'] string Formatting options for paginate fields.
 *                                   Options include 'currency', 'nice',
 *                                  'niceShort', 'timeAgoInWords' or a valid 
 *                                  Date() format)
 *                 ['title'] string Changes the field name shown in views.
 *                 ['desc'] string The description shown in edit/create views.
 *                 ['readonly'] boolean True prevents users from changing the
 *                                 value in edit/create forms.
 *                 ['type'] string Defines the input type used by the Form helper
 *                                  (example 'password')
 *                 ['options'] array Defines a list of string options for drop-
 *                                  down lists.
 *                 ['editor'] boolean If set to True will show a WYSIWYG editor
 *                                  for this field.
 *                 ['default'] string The default value for create forms.

Though using an actual PHP array definition with indentation is even cleaner

虽然使用带有缩进的实际 PHP 数组定义更清晰

回答by Klesun

Among widely accepted key type documenting formats, I'd like to mention few popular ones here:

在广泛接受的密钥类型文档格式中,我想在这里提及一些流行的格式:

Psalm/PHPStan/phanformat

Psalm/ PHPStan/ phan格式

/** @param array{foo: string, bar: int} $args */

as a bonus, can also be used for static code analysiswith their tools

作为奖励,也可以使用他们的工具进行静态代码分析

Wordpressformat

WordPress格式

/**
 * @param array $args {
 *     Optional. An array of arguments.
 *
 *     @type type $key Description. Default 'value'. Accepts 'value', 'value'.
 *                     (aligned with Description, if wraps to a new line)
 *     @type type $key Description.
 * }
 */

and both are supported by deep-assoc-completionplugin

并且两者都由deep-assoc-completion插件支持

回答by jgmjgm

Arrays in PHP are really more like anonymous structs.

PHP 中的数组实际上更像是匿名结构。

For arbitrary data structures there are a number of schema validators but unfortunately it's not widely supported in type hinting. Perhaps some common schemes have plugins? The problem is things working in only one or a few places. You might get the right thing working for your IDE but run static analysis and it can all got to hell.

对于任意数据结构,有许多模式验证器,但不幸的是,它在类型提示中并未得到广泛支持。也许一些常见的方案有插件?问题是事情只在一个或几个地方起作用。您可能会为您的 IDE 做正确的事情,但运行静态分析,它可能会陷入困境。

Care needs to be taken to separate things out so that if possible other tools not supporting a scheme, such as via a plugin, will simply ignore it.

需要注意将事物分开,以便如果可能的话,其他不支持方案的工具(例如通过插件)将简单地忽略它。

PHPDoc tends to be supported everywhere but is also very limited.

PHPDoc 往往在任何地方都得到支持,但也非常有限。

There are often proposals but there's no real good standard. Most solutions are non-standard, not widely supported, partial hacks with limitations or purely superficial (documentation).

经常有建议,但没有真正好的标准。大多数解决方案都是非标准的、没有得到广泛支持的、有局限性的部分黑客攻击或纯粹是肤浅的(文档)。

There are specific implementations in specific places but nothing widespread and dedicated to PHP itself. Though you can make your own schemas in PHP IDE's tend to lack decent code bridges, even those with PHP in the name.

在特定的地方有特定的实现,但没有广泛和专用于 PHP 本身。尽管您可以在 PHP IDE 中创建自己的架构,但往往缺乏合适的代码桥接,即使是那些以 PHP 命名的架构也是如此。

You should define your field struct separately. Your outer data structure is as pseudo code @key fields field[]rather than representing as multi-dimensional arrays. Conceptually and confusingly you can go so far as:

您应该单独定义您的字段结构。您的外部数据结构是伪代码,@key fields field[]而不是表示为多维数组。从概念上和令人困惑的角度来看,您可以做到:

@start struct custom
@key \stdClass *
@end struct

@start struct fields
@key string hostname
@key string databaseName
@key string password
@key int port=1433
@key custom|undefined sublevel
@end struct

@start struct connection
@key fields fields
@end struct

Or steal from C then invent a laguage...

或者从 C 中窃取然后发明一种语言......

struct connection {
    struct fields {
        string hostname;
        string databaseName;
        string password;
        int port = 1433;
        custom optional sublevel {
            stdClass *;
        };
    };
};

You can invent a schema based on structs to allow both flat and nested. Nested should be the default, things should only be defined to be as accessible as they need to be for reuse.

您可以创建基于结构的模式以允许平面和嵌套。嵌套应该是默认值,事物应该只定义为可访问,因为它们需要重用。

An unusual approach is to instead use objects. This doesn't have to entail using interfaces such as array access. In PHP an object wraps an array for properties. It's possible to cast an array to an object (without implementation, only properties) and back.

一种不寻常的方法是改为使用对象。这不一定需要使用诸如数组访问之类的接口。在 PHP 中,一个对象为属性包装了一个数组。可以将数组转换为对象(没有实现,只有属性)并返回。

If you use objects instead as an associative array ($array[$key] versus $object->{$key}) then you can make dummy objects to at least fool the IDE...

如果您使用对象作为关联数组($array[$key] 与 $object->{$key}),那么您可以制作虚拟对象来至少欺骗 IDE...

final class PersonStruct {
    /** @var int */
    public $x;

    /** @var int $y */

    public int $z;
}

Of those three options which may or may not work depends on the tool used.

这三个选项可能有效也可能无效取决于所使用的工具。

You can then lie...

然后你就可以撒谎了……

/** @var PersonStruct $ps */
$ps = (object)['x' => 0, 'y' => 1, 'z' => 2];

/**
 * @param PersonStruct $ps
 * @return PersonStruct
 */
function f(object $ps):object {
    return $ps;
}

/**
 * @param PersonStruct $ps
 * @return PersonStruct
 */
function f(stdClass $ps):stdClass {
    return $ps;
}

The problem with this is that it means converting arrays to objects. That have both performance implications and changes pass by value to pass by reference. Which is faster is debatable. Arrays should in theory be faster, though objects have benefits being references by default and work better with JSON which separates object from array unlike PHP.

问题在于这意味着将数组转换为对象。这既有性能影响,也有按值传递到按引用传递的更改。哪个更快是有争议的。理论上,数组应该更快,尽管对象在默认情况下具有引用的好处,并且与 JSON 一起工作更好,JSON 将对象与数组分开,不像 PHP。

Objects also don't support a property that might not be set very well in regards to type hinting, even though properties in an object are just a PHP array (use ->{key}instead of [key]). There's the potential for other weird things.

对象也不支持在类型提示方面可能设置得不好的属性,即使对象中的属性只是一个 PHP 数组(使用->{key}代替[key])。还有可能出现其他奇怪的事情。

If performance is a real concern, you can turn PHP into a compiled language. In the same way you can extend an interface to make an object compilable you can do the same for where you might do everything with OOP and auto-complete but can then do the equivalent of inlining a class by specifying the property it wraps, then using reflection to pretty much replace uses with the contents of the matching methods, with a few extra bits needed (marking what to inline or convert to procedural, single property to wrap or multiple, etc).

如果性能是一个真正的问题,您可以将 PHP 转换为编译语言。以同样的方式,您可以扩展接口以使对象可编译,您可以在可能使用 OOP 和自动完成的地方做同样的事情,但可以通过指定它包装的属性来执行等效的内联类,然后使用反射几乎用匹配方法的内容替换使用,需要一些额外的位(标记要内联或转换为程序的内容,要包装的单个属性或多个属性等)。

The concept is similar to boxing and unboxing. If you're really insane about SA support and broad support for IDEs (auto-complete, checking, etc), analysers, tools, etc then it might be the only way.

这个概念类似于装箱和拆箱。如果您对 SA 支持和对 IDE(自动完成、检查等)、分析器、工具等的广泛支持真的很疯狂,那么它可能是唯一的方法。