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.
Related
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 am using cakephp 3.x
I made this observation. Functions in controllers and tables are declared as public. Functions in entities are declared as protected. Why can't entities functions be declared as public as well?
This sounds like you have no idea when and why you use the visibility scope. See this question "What is the difference between public, private, and protected?" as well.
In fact nothing prevents you from declaring a public method in an entity, try it. Nothing prevents you from using protected and private in other classes as well. But use them where it makes sense architecture wise. Also entities already have public methods. I suggest you to read the chapter about entities in the book, it explains in detail how entities work, what they are and what they're thought for and what you can do with them.
Entities represent data, the data is accessed through the properties or like an array because the object implements ArrayAccess. To access virtual properties (again, read the chapter) the accessors and mutators are used, which are in fact protected. These methods get called when you try to access a non existing property, see the get() method. They're protected because direct access to them is not desired, it would break the way the entities work. Data is thought to be accessed only through the properties or the get() method so that all entities everywhere work the same.
In well written code the visibility scope usually has a reason. But I've seen bad code where people made things private like crazy without reason, which effectively prevents you from altering the objects behaviour by inheriting them. I haven't checked but I'm pretty sure you won't find a private method in the framework because it is thought to be extended.
Bottom line: Analzye the code and get an understanding of why something is protected if you like to know it. It will be for a different reason from case to case.
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.
I'm reading the Yii blog tutorial. What does this code do
foreach($models as $model)
self::$_items[$type][$model->code]=$model->name;
in the loadItems static function. Where does [$model->code] and $model->name come from and what does this line of code do?
The loadItems() is a static function that loads the available statuses for certain "type" that you need, for example, for comments, or for posts. So for example, it prepares the available "status descriptions" for "posts" just before rendering the "post edit page" so you'll have the needed values in the post status dropdown.
The $model is instantiated inside this static function just before the lines you quoted. It means that while this is indeed static method, which means called without instantiating "Lookup" class, inside of it, it does other things. The Full stop here is to emphasize that a class method is a fully contained unit of code. It can do whatever it needs to do inside. In general, one doesn't need to care about its internals (unless the person is designing and coding those internals, of course) but my point is that you need to grasp two distinct things here - the first is what this function does when referred to from the outside - and this is simply returning the lookup items for a certain class. The second thing is that internally, while being a static function, it instantiates some class objects, in our case objects of the same type - Lookup.
This instantiation is done using Yii's Active Record capabilities - the "findAll()" method which will do the needed SQL for you and return the result set of the found records as an array of instantiated objects of type Lookup.
I hope this clears some... .
I'm just getting into PHP OOP and I'm unclear on what properties I need to declare at the start of a class.
Do I declare properties:
A: that are arguments for methods?
B: are not arguments for methods but are still within a method?
C: that are returned from a method?
Edit For Example
Here's an example userclass I'm trying to create
class user
{
public function selectMember($username,$password)
$query = "SELECT * FROM users WHERE username='$username' && password='$password'";
return $query;
}
So I would have to declare $query only at the top of the class?
The way I think of these things is that an object is a code representation of a real life object (duh). The car example above is a good one. For most real life objects there are attributes and actions. If our object is person, it will have attributes like name, height, weight, hair color. Then, our person will have actions, like run, sleep, eat.
The actions will be methods and the attributes will be properties. Properties will either be used in the actions or by other parts of the program which need to check the state of your object, IE, another part of your program asks the person how tall it is right now.
In most cases, return values and arguments will not be properties. A notable exception would be arguments you use to instantiate an object, as those will typically be needed by your other methods. As far as variables used within a method, these should be properties if they define the overall state of the object, but if you are creating a variable, like a counter, inside your method, that is just needed to accomplish the goal of the method, it doesn't make sense for it to be a property of your object.
I would start out by erring on the side of fewer properties. If you get to a point where you need a property to accomplish something, then create it. I wouldn't create them until I have a direct need. This way, you'll begin to get a feel for what properties an object will need in order to function logically.
I hope that makes a little sense.
Properties are pieces of data about the object. For example, to take the classic car example:
The car's color, make/model, year, etc. are all properties of the car.
There may be a method StartCar that requires a Key object to start. The car does not have a key, therefore the key is not a property -- it is a method argument. But the car does have a lock that is capable of validating a given key. The argument and the property work together to perform the action (or, in this case, validate the action).
Each instance of the car class may have different values for these properties.
If you need specific help deciding what to make into properties, we will need more information about your specific requirements.
Php.net have a real good documentation about PHP OOP
It's pretty much your choice, according to the best answer in "When should I declare variables in a PHP class?".