Best way to document Array options in PHPDoc?

时光怂恿深爱的人放手 提交于 2019-11-29 20:16:05

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'] 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.

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

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 $params should be.

I wrote a plugin for phpstorm that allows specifying keys like this:

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

/**
 * @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][''];
}

It allows to specify @return keys as well:

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

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) {...}

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

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
 */

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.

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

Arrays in PHP are really more like anonymous structs.

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.

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.

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.

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:

@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...

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.

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...

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.

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.

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).

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.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!