This question already has answers here:
PHPDoc for variable-length arrays of arguments
(7 answers)
Closed 5 years ago.
What's the best way to document the elements of an array when it is a parameter to a method? For example, using the PHPDoc headers, I might have something like:
#param array $data
What this doesn't tell me is what elements are mandatory in the array, and what are optional elements. I imagine this should go in the explanation of the method. Something like:
array: $data
============
int $id Required
name $string Required
town $string Optional
/**
* #param array $data
*
* #var $data[id] int, required
* #var $data[name] string, required
* #var $data[town] string, required
*/
This example of using doctrine and zf2 example:
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
* #Form\Attributes({"type":"hidden"})
*/
protected $id;
/**
* #ORM\Column(type="string")
* #Form\Type("Zend\Form\Element\Text")
* #Form\Required({"required":"true"})
* #Form\Filter({"name":"StripTags"})
* #Form\Filter({"name":"StringTrim"})
* #Form\Validator({"name":"StringLength", "options":{"min":"5"}})
* #Form\Options({"label":"First name"})
*/
protected $firstName;
If you have such a complex array with constraints for every single member, I wouldn't use an anonymous array but rather a well defined object. With an array, you can never be sure what it holds, that's somewhat like passing "Object" in e.g. Java, which you rarely would consider a good choice.
However, there is the possibility of a little hinting, when you array contains objects of a certain type as explained here, but that's not a really good answer to your question.
If you really need the parameter as an array, you might document it the way you proposed in the method's description; however, if you use an object as parameter, you'd have additional support in modern IDEs (IntelliSense and so on).
EDIT: I mean, for me the question would be "why would I want to use an anonymous array instead of a self defined type" - and besides simplicity (which will backfire as technical debt later if you maintain and extend your code), I cannot think of a reason, especially compared to what you gain in using a user defined type (self documented code, constraints visible and made explicit by standard methods and so on).
If you just need a dump of data, you might want to go with a simple array, but since you're already thinking about optional and required keys, that screams for a user defined type.
EDIT2: Regarding your comment about if your already have an array as source: I'm not sure whether you need to pass it on as an array or do "mapping" operations as soon as you receive the array (e.g. as $_POST or as return value from some third party library or PHP internal functions or such).
I suppose one could argue that it's not the model's business to interpret data generated by views (e.g. HTML forms which POST data), but rather the controller's resonsibility to react accordingly to the input and transfer the model in the appropriate state. What I mean by this is that you could do something like this if you receive e.g. an array as $_POST:
$customer = new Customer();
$customer->setId($_POST['id']);
$customer->setName($_POST['name']);
$customer->setTown($_POST['town']);
And handle errors as soon as you access the $customer, e.g. throwing exceptions if the name is not set (i.e. $_POST['name'] was empty or such). This way, you use the source array to call setters on the object instead of e.g. passing the array to a factory like Customer::buildByHttpPostData(array $data) and thereby delegating the knowledge of the view's details (names of HTML input tags and such).
Bottom line is, there's no "standard" way to declare required or optional array keys, and of course you can describe those constraints in the method description, but perhaps you can circumvent this by keeping with supported ways like PHPDoc comments on setters or getters.
Of course, there may be better ways to approach the problem, and perhaps somebody comes up with a better answer how to handle it.
To answer the question there is no formal way, try to use a way that you think is most intuitive. I do something similar:
/**
* #param array $data [ int $id, string $name, string $town ]
*/
However I wouldn't use this notation for parameters but rather as return values. In your case I would extract the method arguments to an object and pass that into the method instead:
/**
* #param User $user
*/
public function myMethod( User $user )
{
//...
}
The reason for this is the User object exposes it's properties as an API to other developers, self documenting code!
The other method would be to separate out the array elements into arguments like so:
/**
* #param int $id
* #param string $name
* #param string $town
*/
public function myMethod( $id, $name, $town )
{
//...
}
3 arguments is just about passable but you should start looking for a way to refactor it, like my first suggestion. 4 arguments is generally agreed to be messy and you refactor it.
Related
Say I have a function like this:
function theFunction() {
$arr = array();
for ($i=0;$i<10;$i++) {
$arr[] = new theObject($i);
}
return $arr;
}
I need to document the return type of the function. I could of course just usearray, but that does not provide all the information that can be provided, and doesn't tell the developer much about the true nature of the function.
How do I document the type "array of [type]" in PHPDoc?
From the documentation of phpDocumentor
The value represented by Type can be an array. The type MUST be defined following the format of one of the following options:
unspecified, no definition of the contents of the represented array is given. Example: #return array
specified containing a single type, the Type definition informs the reader of the type of each array element. Only one Type is then expected as element for a given array.
Example: #return int[]
Please note that mixed is also a single type and with this keyword it is possible to indicate that each array element contains any possible type.
specified containing multiple types, the Type definition informs the reader of the type of each array element. Each element can be of any of the given types. Example: #return (int|string)[]
Note
many IDEs probably do not support this notation yet.
In PHPDoc you can do the following for type hinting array members:
#var array<\My\Folder\ClassName>
UPDATE
You can also explicitly declare the key for associative arrays as follows:
#var array<string, \My\Folder\ClassName>
And according to the answer posted here you can even explicitly declare the keys in case you would like to do so like this:
/**
* #return array[
* 'controller' => string,
* 'action' => string
* ]
*/
Note: This is tested and works perfectly well in PHP storm:
If I'm remembering right you supply the return type and a description, can you not put it in the description?
/**
* blah
* #return array array of types
*/
If a function requires an incoming array to have a specific key/index, is there an eloquent way to express it via comments, specifically PHPDoc?
For example:
/**
* Just an example function
* #param array $arr My Example Array
*/
public function myFunction( $arr ){
if(!array_key_exists('mykey', $arr)){
echo 'Damnit, we needed an array that had mykey as an index!';
}
}
You could write a list of such keys, and place it in the #param description, or put it in the long description of the method's docblock. There is nothing "automated" or "rigid" that phpDocumentor could really do in the documentation here, e.g. link to some other documented element.
No, if you need a specific variable, make it a separate parameter. In that case, if the parameter is empty, an error is thrown.
You can't specify the data-type of array values in PHP. So there is noeed to document that via PHPDoc.
NO there is not. Best to just put it in the comments section.
Which of the following is the proper way to document the return type of this method for phpDocumentor?
Method 1:
/**
* #return array Foo array.
*/
public function foo() {
return array(1, 2, 3);
}
Method 2:
/**
* #return integer[] Foo array.
*/
public function foo() {
return array(1, 2, 3);
}
Also, are there any IDE implications from either method?
Edit:
It appears that both PhpStorm and Netbeans 7.1+ IDEs support the 2nd method.
Both methods are technically correct, but this one is considered 'better' because it's more specific (int and integer are interchangeable):
#return int[]
Documented here:
http://www.phpdoc.org/docs/latest/guides/types.html
At the moment of writing this answer, these are the accepted ways of phpDocumentor (and probably other PHPDoc implementations) to denote an array:
unspecified, no definition of the contents of the represented array is
given. Example: #return array
specified containing a single type, the Type definition informs the
reader of the type of each array element. Only one Type is then
expected as element for a given array.
Example: #return int[]
Please note that mixed is also a single type and with this keyword it
is possible to indicate that each array element contains any possible
type.
specified containing multiple types, the Type definition informs the
reader of the type of each array element. Each element can be of any
of the given types. Example: #return (int|string)[]
I was browsing SO and found this hosted code as a recommended way of cutting down on PHP code.
https://github.com/jamierumbelow/codeigniter-base-model
So far, from the methods that I have figured out how to use, I love what it does and how simple it makes things.
However, in the following code:
/**
* Get a single record by creating a WHERE clause by passing
* through a CI AR where() call
*
* #param string $key The key to search by
* #param string $val The value of that key
* #return object
*/
public function get_by() {
$where =& func_get_args();
$this->_set_where($where);
$this->_run_before_get();
$row = $this->db->get($this->_table)
->row();
$this->_run_after_get($row);
return $row;
}
I'm not exactly sure how to make a call to this function.
The description of what it does is exactly what I want to do.
The #params say it takes in a key and value pair for the WHERE block but I don't see any function inputs in the method signature.
Help, please?
As I'm noticing with a lot of CI code, it's strange and maintenance un-friendly.
PHP functions can accept n or more arguments (where n is the number of arguments defined in the signature)
The code makes use of func_get_args() which returns an array of arguments.
The array of arguments is then passed to the _set_where() method which passes either one or two items to the db->where() method.
A more descriptive method signature would have been
public function get_by($key, $val = null)
For future reference, and like Phil mentioned, the *_by methods pass the value through to the db->where method. This means you can use it in a variety of methods:
$row = $this->model->get_by('key', $value);
Or using an array for multiple WHERE conditions:
$row = $this->model->get_by(array('key' => $value, 'other_key !=' => $value));
Or just the string (don't forget to escape your values!):
$row = $this->model->get_by('some_column = ' . $this->db->escape($value));
Since this question was asked, I've thoroughly updated the documentation so now it should all be a little clearer. Hope this helps.
CakePHP makes heavy use of associative arrays for passing large numbers of parameters to functions. I have not really seen this technique outside of PHP and never seen it used to the extent that Cake uses it. I really like this approach because as it seems it would be easier to handle new parameters in future releases of your own code and it's alot more readable than simply a long list of params.
As an example...
function myFunc($params = array('name' => 'rob', 'count' => 5, 'anArray' => array('A string', 5, myObject)))
{
// ...
}
I guess this is similar to using argc/argv, but is a bit easier to read. Does anyone have a list of pros and cons on this method or know of anyone that's written on best practices with this? I've tried just Googling it but "associative array of parameters" brings up pretty much every programming article ever written.
Also, is there even a term for passing parameters this way?
A downside to using named parameters is documenting the parameters with PHPDoc. Many editors/IDEs provide "automatic" documentation that can parse your code and generate generic docblocks.
e.g.
function foo(array $bar, SomeClass $stuff) { returns $magic; }
would produce:
/**
* foo
*
* #param array $bar
* #param SomeClass $stuff
* #return mixed
*/
function foo(array $bar, SomeClass $stuff) { returns $magic; }
If you put all your parameters in a $params array, it would only look like
/**
* foo
*
* #param array $params
* #return mixed
*/
It also adds a lot of additional burden to your developers to have to type the extra code for each parameter. I'd suggest using a mix of the two approaches.
e.g. If you had a function to return an HTML text input element you could have the following method signature:
/**
* formText
*
* #param string $name name of text element
* #param string $value value of text element
* #param array $options additional options for text element
* #return string
*/
function formText($name, $value, $options = array());
Thus, you can easily pass the most common values to the function.
$this->formText('foo', 'Default...');
and if you need additional, less common params you'd use the convenient named parameter syntax:
$this->formText('foo', 'Default...', array(
'class' => 'bold highlighted'
));
otherwise, using only a generic $params array you'd have to type:
$this->formText(array(
'name' => 'foo',
'value' => 'Default...'
));
It is a emulation of using keyword arguments. In python, for example, you can say:
myFunc(name="bob", age=10, gender="male")
Since PHP does not support this syntax, associative arrays are the next-best-thing.
Other high-level languages support named parameters to functions and methods. For instance, in Python you can call:
my_func(name='rob', count=5, an_array=['A string', 5, my_object])
What you are seeing is an attempt to simulate this behavior in PHP. The benefits are obvious.
Flexibility
No need to know order/number of expected parameters
One drawbacks might be that a hash table lookup is required for every method call, but depending on how arguments are handled in PHP, the performance hit may be negligible.
It's the only way to do named parameters in PHP.
It's only useful when you have a large number of arguments, IMO. Otherwise the benefits of an explicitly defined argument signature are the better choice, especially if you use an "intellisense" capable IDE.
This technique is (really) often used in Javascript, with objects (when you are using string as keys, in JS, you are using objects, not arrays) ; for an example, see scriptaculous Draggable.
Now, for a couple of pros and cons that immediatly come to mind :
pro : you can use any number of parameters you want, and still have them named
and there is no "only parameters at the end of the list are optionnal"
con : phpdoc is not fine : it seems there is only one parameter, and there is not much indication on what it does
con (consequence of the previous one) : when you are using an IDE with code-hints, it cannot display names/description for each parameter : you always have to check the documentation.
That single "con" is enough for me : I only use that way of passing parameters if there is no other (reallistic) way.