J'ai du mal à écrire une documentation lisible et facile à comprendre qui décrit la structure multi-arborescente pour les options de tableau qui sont passées à une fonction.
Voici un exemple de structure de tableau.
$arr = array(
'fields'=>array(
'title'=>array('name'=>'Document.title','format'=>'string','readonly'=>true)
)
);
Il existe de nombreuses options possibles pour le tableau ci-dessus, mais cela est utilisé comme paramètre d'une fonction qui comprend cette structure.
function doSomething(array $arr) {...}
Je voudrais documenter la façon dont le tableau doit être structuré en PHPDoc, mais je ne sais pas quelle est la bonne approche.
Voici ce que j'ai maintenant.
/**
* 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.
**/
Mon problème est que lorsque le document HTML est généré, il n'est pas très bien formaté. De plus, je ne suis pas sûr que ce qui précède explique clairement la structure du tableau.
Existe-t-il une approche alternative?
Le simple fait d'ajouter une tabulation le rendra beau et facile à comprendre
/**
* 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.
**/
Une approche par liste imbriquée:
<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>
Résultat:
Si vous voulez qu'il ait l'air chic, avec un peu de Css ça fera des merveilles! xd
Un peu trop tard pour la fête mais voici comment je le fais à la place:
/**
* 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){}
Je pense que c'est assez propre et facile à comprendre ce que $params
devrait être.
J'ai écrit un plugin pour phpstorm qui permet de spécifier des clés comme ceci:
(fondamentalement juste une version légèrement plus stricte du format de @ 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][''];
}
Il permet de spécifier @return
touches également:
/**
* @return array [
* 'success' => true,
* 'formObject' => new Form,
* 'errors' => [],
* ]
*/
public static function processForm($arr);
Pouvez-vous utiliser des objets au lieu de tableaux? Cela faciliterait la documentation.
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;
}
//...
}
Ensuite, vous pouvez utiliser un indice de type où la classe est requise.
/**
* Do something.
* @param FieldList $field_list The field.
*/
function doSomething(FieldList $field_list) {...}
Markdown Syntax for Object Notation (MSON) peut être un meilleur choix.
exemple
/**
* @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
*/
J'aime mieux ça:
* @param array $doc
* 'type'=>Doc::MY_DOC_TYPE,
* 'created'=>$now,
* 'modified'=>$now
Je viens de coller le code d'où il est initialisé, rapidement et facilement.
Comme il s'agit uniquement d'un affichage plutôt que d'une directive, et devrait conserver la mise en forme de l'espace dans les documents, je serais enclin à opter pour la lisibilité avec une indentation plutôt qu'un mur de caractères:
* 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.
Bien que l'utilisation d'une réelle PHP avec indentation soit encore plus propre
Les tableaux dans PHP sont vraiment plus comme des structures anonymes.
Pour les structures de données arbitraires, il existe un certain nombre de validateurs de schéma, mais malheureusement, il n'est pas largement pris en charge dans les indications de type. Peut-être que certains schémas courants ont des plugins? Le problème, c'est que les choses ne fonctionnent que dans un ou quelques endroits. Vous pourriez obtenir la bonne chose pour votre IDE mais exécutez une analyse statique et tout peut aller au diable.
Il faut prendre soin de séparer les choses afin que, si possible, d'autres outils ne prenant pas en charge un schéma, comme via un plugin, l'ignorent simplement.
PHPDoc a tendance à être pris en charge partout mais est également très limité.
Il y a souvent des propositions mais il n'y a pas de vrai bon standard. La plupart des solutions sont des hacks partiels non standard, non largement supportés, avec des limitations ou purement superficiels (documentation).
Il existe des implémentations spécifiques dans des endroits spécifiques mais rien de répandu et dédié à PHP lui-même. Bien que vous puissiez créer vos propres schémas dans PHP les IDE ont tendance à manquer de ponts de code décents) , même ceux avec PHP dans le nom.
Vous devez définir votre structure de champ séparément. Votre structure de données externe est sous forme de pseudo-code @key fields field[]
plutôt que de représenter des tableaux multidimensionnels. Sur le plan conceptuel et confus, vous pouvez aller jusqu'à:
@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
Ou voler à C puis inventer un laguage ...
struct connection {
struct fields {
string hostname;
string databaseName;
string password;
int port = 1433;
custom optional sublevel {
stdClass *;
};
};
};
Vous pouvez inventer un schéma basé sur des structures pour permettre à la fois plat et imbriqué. Imbriqué devrait être la valeur par défaut, les choses ne devraient être définies que pour être aussi accessibles qu'elles doivent l'être pour être réutilisées.
Une approche inhabituelle consiste à utiliser des objets à la place. Cela ne doit pas impliquer l'utilisation d'interfaces telles que l'accès aux baies. Dans PHP un objet encapsule un tableau pour les propriétés. Il est possible de transtyper un tableau en un objet (sans implémentation, uniquement des propriétés) et inversement.
Si vous utilisez des objets à la place comme tableau associatif ($ array [$ key] contre $ object -> {$ key}), vous pouvez créer des objets factices pour tromper au moins l'IDE ...
final class PersonStruct {
/** @var int */
public $x;
/** @var int $y */
public int $z;
}
De ces trois options qui peuvent ou non fonctionner dépend de l'outil utilisé.
Vous pouvez alors mentir ...
/** @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;
}
Le problème est que cela signifie convertir des tableaux en objets. Cela a à la fois des implications en termes de performances et des modifications passant par valeur pour passer par référence. Ce qui est plus rapide est discutable. Les tableaux devraient en théorie être plus rapides, bien que les objets aient l'avantage d'être des références par défaut et fonctionnent mieux avec JSON qui sépare l'objet du tableau contrairement à PHP.
Les objets ne prennent pas non plus en charge une propriété qui pourrait ne pas être très bien définie en ce qui concerne l'indication de type, même si les propriétés d'un objet ne sont qu'un tableau PHP (utilisez ->{key}
au lieu de [key]
). Il y a le potentiel pour d'autres choses étranges.
Si les performances sont un réel problème, vous pouvez transformer PHP en un langage compilé. De la même manière, vous pouvez étendre une interface pour rendre un objet compilable, vous pouvez faire de même là où vous pourriez tout faire avec OOP et saisie semi-automatique, mais peut alors faire l'équivalent d'inliner une classe en spécifiant la propriété qu'elle encapsule, puis en utilisant la réflexion pour remplacer à peu près les utilisations par le contenu des méthodes correspondantes, avec un peu de bits supplémentaires nécessaires (marquant ce qu'il faut aligner ou convertir en procédural, propriété unique à envelopper ou multiple, etc.).
Le concept est similaire à la boxe et au déballage. Si vous êtes vraiment fou de SA et large prise en charge des IDE (saisie semi-automatique, vérification, etc.), des analyseurs, des outils, etc., cela pourrait être le seul moyen.