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.
Related
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:
I know this is kind of a question of faith and has been asked many times before, but the answers I've found were either too general, didn't apply to my use case, or didn't satisfy otherwise.
I'm currently building an application that uses classes as representation for database tables. These classes don't offer any methods of their own, I've written a parser class for each one that works with their objects and returns the data in the format I need, which makes the parent classes nothing more than data storages and makes a nice distinction between data and logic.
Now, the consensus in OOP seems to be that you always have to use getters and setters instead of accessing class attributes directly.
An argument I've often heard is that using getters and setters gives the possibility of extending those functions later on, but in my opinion this goes against YAGNI and some other concepts I can't remember the name of right now - that a method should do exactly what you would expect from its name. If I wanted to do something more than simply set a value, I would write a new method, not put that into my setter method, since that one is, per definition, only supposed to set attributes. So I might as well skip the setter and just access the attribute directly.
Another one is that you can put validation in your setters, which I already do in my API that accesses these classes. In my opinion you shouldn't just pass values and have the object tell you if your value is okay or not, but instead validate those values first before you pass them to the object.
I do understand the purpose of private/protected attributes in "usual" classes, but when the class is literally just a data container without any methods, is this really needed? In other words: is there a glaring disadvantage to using public values, when the setter methods for those (were they private) would all just look like public function getAttr($attr) { $this->atrr = $attr; } anyway?
You only need a data structure, but the only suitable PHP construct is the class.
Typically, in object-oriented analysis, design and programming, a class is a model of a thing or concept and it encapsulates any knowledge and/or behaviour of the thing or concept.
However, in the context of this question, encapsulation is not needed since you only require a data structure.
I have a problem (this is not really a problem) with PhpStorm. I'm writing in pure PHP and HTML in Zend2 Views and I need to get autocomplete (Ctrl + Space) methods from all Zend ViewHelpers.
I created CustomPhpRender class that inherits from real Zend PhpRenderer.
I cannot find a solution, how can I virtually add all methods from e.g. Form ViewHelper in one line (in PHPDoc). Instead of this, of course, I can write all #method class for every method I need to get in autocomplete.
Have you got any solution how can I do it?
As far as I know, phpStorm will not auto-write the required functions for you. It will give you warnings are far as what is required. I believe it will auto-complete the function declaration for you when you go to declare a required function. It will offer a suggestion and then you hit tab. I've extended classes multiple times, and this is how it has always done it for me.
I have a class that is based on an interface. The methods are correctly documented in the interface, however they only show up as hints if you do not document the method in the implementation class at all. (that is no docblock).
I'd like to put some form of docblock in, rather than just nothing, as it just seems a bit wrong having a method with nothing above it at all and it looks like the documentation has been forgotten. I've tried an empty block and #see, neither of which work (both break autocomplete further up the chain). Ideas?
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.