How to make PHP getter/setter inherit DocBlock from their field? - php

How can I make getter/setter methods to automatically use DocBlock description from their respective fields? Or maybe there are any other ways to solve this: see DocBlocks on getters/setters without manually copy-pasting every single one.
Consider this example:
There is some comment on field $name (1), however, it will almost never be seen as the field is private and intended to be used with getter/setter methods. However, on those methods IDE does not show any comments from field variables (2).
You can, of course, simply copy-paste same description to both methods. But it becomes very difficult to manage when object has a dozen or more properties, all with getters/setters and extensively commented. It requires a lot of manual work to fix the same text in 3 places on every change and is very error-prone.
IDE is PhpStorm.
I'd prefer to do it without magic __get __set methods.

The only option I know is using #see or #link. We can use them inline as well. This is how it looks in Phpstorm:
The link in the description is clickable. Without a mouse, we can use a tab key to move a cursor on the link (3 x tab and enter).
Final view:

Related

PHPdoc for dynamic magic properties (or methods)

I recently created a class to create HTML elements. Instead of bothering by creating a method for every existing HTML element and attributes, I decided to use magic methods __get and __call. So with my code I can basically do this:
$signUpForm->insert->input->type('text')->name('firstName')->maxlength(100)->disabled
$signUpForm->insert->input->type('email')->name('emailAddress')->maxlength(100)
etc.
But since I decided to keep this "magic" and simple, I could also do this:
$signUpForm->insert->magic->trick('rabbit')->accessory('hat') which would result into:
<magic trick='rabbit' accessory='hat'>
This is all good since in my opinion it cuts down a lot of boilerplate code and does exactly what I need to do. I don't want a class to enforce HTML standards, I want a class to facilitate HTML, given you know how to use it (and honestly the code to do this is tiny)
So my question is, considering this class can accept any undefined property or methods, is there any way to specify this behavior in PHPDoc? I tried the following without any luck:
/**
* #property HtmlElementAttribute * Insert a new HTML element attribute
* #method HtmlElementAttribute * Insert a new HTML element attribute
*/
I don't know if this is just a PHPStorm thing but I couldn't find any similar scenario anywhere...
Also if you are wondering why I would do such a thing, it is to keep track of certain HTML aspects in my PHP code (e.g. IDs declared in a form, or elements inside a form). This can allow me to have visibility in my HTML before its send to the end user.
The question is still languishing in the unanswered list, so I'm going to answer it.
For good code intelligence in PhpStorm or Sublime when using auto-magical methods like __get() and __call(), you need to include an #property or #method line for each implicit property or method you add. I know this sucks but it's the cost of using such methods.
Please consider when using __get() if you're really getting enough bang for your buck. It might be right for your app, in which case it's fine. We usually use it when we're trying to do further processing or abstraction on object data (such as camel-case name conversion). You save some code (which PhpStorm will write for you anyway) but you'll need to write the PhpDoc DocBlock lines in the class.
Consider including all of the lines, if for no other reason, than to document your class. With implicit properties you're not only making it hard for the IDE to know what methods and attributes are valid members, but you're making it difficult for the next maintainer. Those docblock lines might seem superfluous but they are great documentation.

Symfony, getters and setters vs magic methods

I don't like having "stupid" getters and setters for every property on my entity classes so I am thinking on using magic methods to get/set those properties instead of creating every single getter and setter. The idea is to create an specific getter or setter when its logic is diffefent from the typical "return $name" or "$this->name=$name". Moreover this magic method would be created on a different class and every entity would extend it (I have not thought very much about this step)
Anyway, what do you think about replacing getters/setters with magic methods?? Would it penalize too much the performance? Any other problems that I am not taking into account?
The problem with that is that e.g. the default template engine of symfony2 twig needs these methods. Twig translates the statement {{ object.property }} to $object->getProperty() so instead of using the very nice dot notation you would have to call properties in twig like this: {{ object.__get("property") }}.
I know that doctrine also uses magic methods in it's entity manager. So when you make a repository query for an object you can use:
$repository->findOneByProperty($value);
instead of
$repository->findOneBy(array(
'property' => $value
));
I would highly suggest that you do not use magic methods but instead use a get and set method for each property separately. This will also give you higher control about the state of that property.
Also be sure to checkout this Answer. It pretty much answers your question aswell.
If you are referring to Doctrine Entity and you have nothing against code generation, you can use the doctrine:generate:entities command, eg.:
$ php app/console doctrine:generate:entities Acme/StoreBundle/Entity/Product
as explained in the documentation.
Therefore you would only need to specify the fields.
Code completion in IDE will not work in this case.
Also you will be not able to make type hinting for object and arrays, and also not with the doc block.
Performance will be slower but depending your project (server hardware and count of useres) you will probably don't see any differences

Document dynamic member variables

I document model classes (in PHP) with Doxygen. I am using Idiorm & Paris as an ORM and I would like the dynamic member variables (coming straight from the database) also to appear in the generated documentation.
Example: I have a model Group with some methods like isMember() or users() documented with Doxygen. In the database I have a table group with a field code among others. In Idiorm & Paris I can access it from a Group instance $group like this:
$group->code
How can I document code in Doxygen?
Edit: This question is similar to How to document a variable that isn't really there in Doxygen?, but it's about dynamic members, not about variables.
Edit 2: I am unsure about the right terminology. It is a dynamic member variable or a dynamic property?
Something I usually do when setting up models for which I know they will contain certain bits of data is setting the variables in the model definition. This makes it easier to see what kinds of data I can expect with the model.
I have no experience with Idiorm nor Paris, but it is something you could try. Documenting the variable is then very easy, because it exists.
Is it impossible to document non-existant class variables in Doxygen? I tried a naked
/** #var User::email string
* Email address
*/
without a corresponding $email; member variable in the class, but Doxygen valiantly ignored that. I didn't find a command or something to force a documentation of a missing artifact.
Therefore I experimented with creativedutchmen's suggestion, however Paris does not cope well with already existing member variables, because – I think – the PHP magic method __get() does not get triggered anymore. I see three possible fixes:
unset() the documented member variables in the constructor. With get_class_vars(get_class($this)) this could be done in a parent class. Because my model classes all inherit from a parent class, this would be relatively straightforward.
Modify Paris to ignore already set member variables, but I do not see how without unset().
Name the member variables slightly differently, like appending an underscore, so they don't conflict with the dynamic variables.
Horrible kludges. To do something at runtime or have additional members to make documentation possible? No thanks.
I decided to leave the situation as-is and document the model factory methods carefully instead. Most of the time the factory methods contains as parameters the class variables to be able to set them. And even if the factory method does not set all class variables, it is possible to document the missing variables in prose. The class documentation is also a good alternative.
I award the bounty to creativedutchmen because of thinking out of the box, even if it didn't help me in the end and because I don't want the reputation points to get lost.
tl;dr
Don't kludge. Document dynamic member variables in the factory method or in the class overview.

Code completion for CakePHP in IDE

Someone recommended I "use code completion" and I realized that while my IDE has code completion, it doesn't recognize the large majority of methods and variables inherited from CakePHP's framework, most notably the Helper methods for views. I'm using PhpED but it seems like it's code completion is supposed to work just as it does in eclipse and other editors.
I followed this advice to no avail; I created a helpers.php file with definitions of all the helpers and included it in the project but the code completion still doesn't work with the Helpers.
I think part of the problem is Mark Story's post is from an old version of cake (I am on Cake 1.3) so I updated the definitions of the Helpers to look like this:
$this->Form = new FormHelper();
But there's still no code completion for any of the views. Is there any way to make this work? In addition to the Helpers I'd really like completion for functions like Model->find() but those don't work either.
as you might have noticed from several working code completion scripts out there you always need to put them into scope.
meaning:
you need to wrap them with the class they should be used in.
at least for components and models etc.
for helpers this is more difficult since they would be in the View scope which is not directly available/visible for IDEs in the views/layouts.
i use the app helper as scope. works for me anyway. more correct would be View class.
either way there is probably not a foolproof method for helpers. most IDE should pick it up, though.
e.g. mine (for phpdesigner):
http://www.dereuromark.de/tag/code-completion/
but the others are similar.
For PhpED you have to do the following to enable Autocompletion for $this.
Lets say you want to use $this in a Controller for something like this
$this->Project->Country->getCountryName($countryId)
First add this PhpDoc tag before the class definition
/**
* #property-read Project $Project
*/
class ProjectsController....
Now typing $this->Project should work as intended.
Next up is the Project model class.
In here add the following code, again before the class definition
/**
* #property-read Country $Country
*/
class Project extends AppModel
Now $this->Project->Country->getCountryName($countryId) works. The method is not 100% as i would like it, as PhpEDs Autocompletion sorts alphabetically, so any class starting with A or B will be shown before the methods of the Country mode.
This is not an answer to your question.
I would recommend gedit, with the word completion plugin. While not an IDE-level "Code Completion" plugin, it does an awesome job at picking up words from your source files and using those to populate its word list. It "just works" for nearly any framework, any language, because of that organic approach to building the word list. (Shameless plug to my blog, with lots of tips and tricks for how gedit can be the best editor out there: http://davidsouther.com/2011/08/gedit-tips-tricks/)

PHP autodoc(Inheritance) autodocumentor tags

I am using phpautodocumentor, I am writing a class which extends a class which is in completely different folder, How can I write in comments that I am extending that particular class. Because intellisense in visual studio or Aptana doesn't recognize. The code works fine.The problem is documenting. It doesn't say I am extending so and so class in documentation
There's no tag for extending, your IDE should realize it from the code, good ones - like PDT, Zend Studio or PhpStorm - do. However, there's a #see tag to refer to other content in the docs.
/**
* this class extends main_class.
* #see main_class, TEST_CONST
*/
subclass extends main_class {
}
(from the perspective of phpDocumentor, docblocks in general, and IDE popup help...)
Ideally, the IDE should recognize from the code that the current class is a child of another class, and show you info from the parent docblock on the child class's popup help. However, if you put a docblock on the child class itself and write info there that duplicates sections from the parent docblock (short description, long description, #param, #return), then the child docblock info will sometimes "override" the parent info, effectively preventing the popup from showing any parent info at all.
If I make a docblock on a child class or inherited items, I'll stick with only using tags in them other than #param and #return, so that the child docblock info augments the parent info rather than replace it. Generally, though, I won't put a docblock on inherited methods since I don't need it to show anything beyond what's already given in the parent's docblock.
(from the perspective of "phpautodocumentor", which I don't know of, and Aptana, which I don't use but is presumed to be an Eclipse derivative...)
I have assumed that you are mainly referring to the IDE's popup help showing you parent class info when you highlight the child class.
Instead, if you are referring to something that is generating actual class documentation separately from IDE file editing, then nothing should generally be required other than the code itself. phpDocumentor certainly recognizes class inheritance from the code alone, and will show inherited things in their own section in most of the output converters. If "phpautodocumentor" is something else, then I can't speak to what its capabilities are.

Categories