We have a bunch of classes, interfaces, etc. in Drupal 7 that are lacking in documentation, or at least I think so.

http://drupal.org/node/1354 is the doxygen standards. It doesn't really say much of anything about classes, interfaces, methods, member variables, etc.

Questions:
a) Should all classes have a doxygen doc header?
b) Should all interfaces have a doxygen doc header?
c) Should all methods in classes and interfaces have a doxygen header?
d) Should all member variables (public? private? protected?) have a doxygen header?
e) If a particular class extends another class and/or implements one or more interfaces, do we still need to have doc headers for the methods that it is overriding/implementing? If so, can we use an abbreviated format, like what we do for hook implementations?

My proposed standards:

All classes, interfaces, public/protected methods, and public/protected member variables must have documentation headers. Private methods and member variables can also have documentation headers.

give an example here of a class with 1 method and 1 variable.

If a method overrides or implements a method on a class it inherits or an interface it implements, an abbreviated format can be used for the documentation header:

/**
 * Overrides class FooBar::myMethod().
 */

/**
 * Implements interface FooBar::myMethod().
 */

Thoughts?

We need to figure this out soon, so we can fix #718576: [Meta] API documentation for classes and interfaces is incomplete in the appropriate way.

Comments

stella’s picture

I think I would like doxygen documentation for all of the above. :)

Should all member variables (public? private? protected?) have a doxygen header?

+1 for documenting them, but I'd like to see an example for the formatting you're proposing here.

If a particular class extends another class and/or implements one or more interfaces, do we still need to have doc headers for the methods that it is overriding/implementing? If so, can we use an abbreviated format, like what we do for hook implementations?

I think we could use an abbreviated format - for the 1st one line sentence, but I'd like to see a more detailed description following it, which we don't require for hook implementations.

Cheers,
Stella

Crell’s picture

A, B, C, D: Yes, yes, yes yes. Anything without a *complete* docblock is a bug, with a caveat for E below.

E: My concern here is that many many IDEs and documentation parsing programs (real Doxygen, PHPDoc, etc.) will, when they detect a parent class/interface, inherit its documentation. If there is an over-ride docblock, I'm not sure how they handle it.

Before making a decision on E, I'd want to see how such supporting programs handle it and what they prefer. We'd want to at least look at Eclipse and Komodo for IDEs and PHPDocumentor for doc parsers. Then follow their preference.

jhodgdon’s picture

Hre's a proposal:

/**
 * Represents a prepared statement.
 */
interface DatabaseStatementInterface extends Traversable {

  /**
   * Executes a prepared statement.
   *
   * @param array $args
   *   Array of values to substitute into the query.
   * @param array $options
   *   Array of options for this query.
   *
   * @return
   *   TRUE on success, FALSE on failure.
   */
  public function execute($args = array(), $options = array());
}

/**
 * Represents a prepared statement.
 *
 * Default implementation of DatabaseStatementInterface.
 */
class DatabaseStatementBase extends PDOStatement implements DatabaseStatementInterface {

  /**
   * The database connection object for this statement DatabaseConnection.
   *
   * @var DatabaseConnection
   */
  public $dbh;

  /**
   * Constructs a DatabaseStatementBase object.
   *
   * @param DatabaseConnection $dbh
   *   Database connection object.
   */
  protected function __construct($dbh) {
    // Function body here.
  }

  /**
   * Implements DatabaseStatementInterface::execute().
   */
  public function execute($args = array(), $options = array()) {
    // Function body here.
  }

  /**
   * Returns the foo information.
   *
   * @return object
   *   The foo information as an object.
   */
  public function getFoo() {
    // Function body here.
  }

  /**
   * Overrides PDOStatement::fetchAssoc().
   */
  public function fetchAssoc() {
    // Call PDOStatement::fetch to fetch the row.
    return $this->fetch(PDO::FETCH_ASSOC);
  }
}

NOTES:
- Check out http://us3.php.net/manual/en/class.pdo.php -- that's where I got the idea that "Represents" would be a good idea for the first verb in a class. Not sure about interfaces?
- I'm looking for more references to how other projects are doing this...
- I am not sure whether the API module supports @var, but this is correct usage: http://manual.phpdoc.org/HTMLSmartyConverter/HandS/phpDocumentor/tutoria...

jhodgdon’s picture

Here's information on inheritance of docblocks in PHPDocumentor -- it looks like it applies to the classes and methods, but it doesn't say anything about inheritance from interfaces specifically:

http://manual.phpdoc.org/HTMLSmartyConverter/HandS/phpDocumentor/tutoria...

I still think it would be better for our purposes if we had a doc block like what I put in #3 for methods we are overriding. And will the API module do the right thing and create us a page for the method if it has no doc block at all?

Berdir’s picture

What about "Implements... " for methods that.. well, implement an interface? We already use that for hooks and it is imho the correct technical description.

jhodgdon’s picture

Berdir: I totally agree with you, and that standard is in my example proposed in #3.

I used "Overrides" for a method that overrides the same method in the base class.

Crell’s picture

API module doesn't do anything with classes either way, so we can define what it will do. (Or just use PHPDoc. :-)) We can probably assume interfaces will work the same as classes.

From an IDE perspective, short description and @return are the most important to have working. (@param less so because we can also type hint in the method signature itself, but it's still important.) Long description we don't need as much.

I'd rather not be always throwing "implements" on everything. For one thing, it's not an implements. :-) Implements is for hooks, and method overrides are not hooks. If we want to start using implements here, then we shouldn't use it for hooks, since they're not the same thing.

jhodgdon’s picture

Umm... I think it is implements when it's a class implementing an interface, and the method is implementing the interface's method, isn't it? I mean, I think that is the technical term for class/interface? But when you extend a class, I think you override the class's previous definition of the method. ??

As far as what hooks do, I think it really is the same thing just without the OOP. I mean, you could think of Drupal as one big interface, and the hooks are the methods your "class" (module) can choose to implement.

Crell’s picture

Yes, "implement" is the standard OO terminology. I don't think it's necessary here, though, as it is already implicit in the class definition itself (class Foo implements Bar). The only question is which method relates to which interface. For that, we should go with whatever format ties into IDEs and doc parsers best. For overrides, a place to describe why we are overriding a parent class's method (assuming it's not an abstract method, in which case the reason is self-evident) would be useful as well.

And no, hooks and OO interfaces are not at all the same thing. I really really wish people would stop confusing modules with classes, as it's a very misleading and harmful assumption. :-)

An Interface in the OO sense is a very specific syntactic construct. That can unfortunately be confused with an "application programming interface", which is more abstract and can be any defined set of operations to instruct code to do something. English is, sadly, quickly running out of nouns for us to use. Hooks as Drupal uses them are a specific procedural implementation of the observer pattern using tricks of PHP to be really really fast. And then there's magic callbacks, which we call hooks even though they are not. Those generally should be methods of a class instead, but that's a Drupal 8 task to fix.

jhodgdon’s picture

OK...

So can you suggest specific changes to my proposal in #3, or is it OK as is?

Crell’s picture

What do doxygen, PHPDoc, and Eclipse do with the "Overrides", "Implements" docblock headers? Do they pass through anything, or do they override entirely? I do not like those at all, unless they are actually directly supported by the available tools.

Berdir’s picture

Atleast NetBeans doesn't display the interface documentation, it's irrelevant if there is a docblock or not. Though that could probably be changed with the nbdrupal plugin, but that's a different story :)

jhodgdon’s picture

Well, right now I don't think the API module is doing anything with classes and interfaces at all.

PHPDoc supposedly will inherit most of the stuff (@param, @return, short description, long description, etc.) from any methods that are being implemented/overridden by methods in a class (see link I put on #4).

I am not sure about Eclipse.

jhodgdon’s picture

One other thing to consider is someone looking at the code itself. I personally think that the style suggested in #3 will give someone guidance as to where to look for the more complete docblock, whereas leaving the docblock off entirely (which is perfectly fine for PHPDoc) gives nothing.

On api.drupal.org, the style suggested would presumably be translated into a link to the more complete docblock. I would hope.

Crell’s picture

I will check to see what Eclipse does and report back.

mikey_p’s picture

#710774: Ensure all class-related items are parsed is the related issue from API module.

jhodgdon’s picture

bump. There is a critical Drupal issue depending on this: #718576: [Meta] API documentation for classes and interfaces is incomplete

So we really need to resolve it.

An update on the status of the API module:
- drumm now has it parsing class/interface items. Methods work the same as non-object functions (@param, @return, etc.), except that they're marked as being part of a class.
- We still need to make a UI for displaying pages for classes/interfaces and their methods. How they should be displayed is still open for debate/influence. If you have an opinion, here's the issue on having a UI for displaying classes:
#757568: Add UI pages for classes
- Automatic understanding of inheritance is unlikely to happen in this pass of the API module.

Crell’s picture

Gah. Sorry, this slipped off my radar.

I've tested both Eclipse and NetBeans, and much to my irritation it looks like neither one does any sort of docblock inheritance for code-assistance. Eclipse's code assistance is particularly awful and half the time or more doesn't trigger at all. NetBeans is much more reliable, but doesn't scan up the inheritance tree. Bugger.

So for PHPDoc, we don't need to specify anything. For IDEs, we would want to specify at least the @return, since that's the most important for them (assuming it's typed), and potentially the short description. I really want to avoid just replicating the entire docblock, though. Aside from making the code harder to read, I'm certain that it will quickly get out of sync.

jhodgdon’s picture

Hmmm.

Maybe we should think about something else... Like we could conceivably add to the API module with an @inherits tag, which could grab the @param/@return/description from the method it inherits from. But of course that wouldn't help for the IDEs.

Sigh.

We need something that is:
a) Maintainable.
b) Clear when you are reading the PHP file.
c) Helpful for IDEs.
d) Set up to display well on api.drupal.org. Ideally, it would grab missing parts (description, param/return, etc.) from the methods that are being overridden or implemented, and ideally it would display on a class page any methods/variables that aren't overridden from the parent class that is being extended.

It may not be possible to satisfy all of the above.

I think the proposal in #3 would be OK for a, b, and d (assuming we get the API module to do the required work). Not so good for (c).

Anyone have any more ideas? Should we adopt #3 or change it in some way?

Crell’s picture

An API parser should be able to derive D from the language itself, without need of docblock assistance. I don't know if api.module does, but I believe phpDocumentor does.

It sounds like A and C are at odds, given that IDEs apparently don't parse up the tree (bastards). However, duplication in the name of B is also at odds with A.

Anyone know how Zend Framework, Symfony, etc. handle this?

jhodgdon’s picture

Agreed: API module should be able to derive D. We'd need to file an issue on the API module to make it happen. At the moment, there are no pages for classes at all -- it's being worked on.
#757568: Add UI pages for classes

mikey_p’s picture

@Crell in #20

As far as I can tell from my forays into Cake and Symfony, they have no ways of handling this either. It seems many common tasks in Symfony w/ Doctrine actually end up using magic methods, so there is really no chance of any IDE having any docs at all.

The only place I've seen any sort of magic method issue in Drupal is with Database query extenders, which cannot have a helpful @return value, since the returned class is set at runtime. There could certainly be more examples of this, I am just not aware of them.

sime’s picture

I think we should OK #3 to go into the coding standards. I don't think the final version will differ much.

Speaking to Drumm, the classes are being parsed to the detail we need, and it is theoretically possible to build a complex API documentation interface without and additional doxygen style markup.

So then we just need to evaluate the need for @inherits or @overrides. I'm working on api.module over the next couple days and hope I can provide some feedback.

jhodgdon’s picture

If we might need tags in order to accomplish what we want with api.module, let's table the discussion of the standard until we've decided if we need them or not. Either we put them in plain text (as in #3 proposal above), or we use tags. I don't want to set the standard, start documenting the classes (which is URGENT), and then have to go back and fix them.

DevElCuy’s picture

if I understood well:
- a proposal was sent at #3 and seems that there is some consensus to adopt it
- before solving this issue, api.module needs some work as noted in #21 (see: #757568: Add UI pages for classes)
- Doxygen presumably works "as is" for point D in #3 as noted in #23

Crell’s picture

@inherits and @overrides do not need any parser support. The parser can get that out of the code already; there's no need to introduce redundant information.

The problem with #3 is that it doesn't have any benefit for people while actually writing code. Showing that Foo::bar() overrides Baz::bar() doesn't tell me anything about what bar() actually does or how to use it.

jhodgdon’s picture

Yeah, that's true. But it's also true of our "Implements hook_foo()." headers for Drupal hooks. I don't think this is much different or much worse, and I was overruled when I suggested we should have full doc headers for hooks, a few months back.

Thoughts?

sun’s picture

a) There's a difference between "Implements Foo::bar()." for interface implementations and "Extends/Overrides Foo::bar()." for extended classes, no?

b) If the parser can properly figure out relationships automatically, then we shouldn't add explicit documentation. Like for hook implementations, we'd rather have to think about an ideal API UI to display derived documentation (in a separate issue).

jhodgdon’s picture

a) Yes. See sample in #3 above.

b) I still think we need a docblock. The API module doesn't generally create a doc page for things without docblocks. Also, we need to consider that some people will just be reading the code and not on an API site.

jhodgdon’s picture

I just talked to drumm, and the API module will not require us to put a header at all on a method to figure out which interface method is being implemented or base class method is being overridden. The parser will figure this out itself.

So from drumm/api.module perspective, we can completely leave out headers on methods.

We also don't need @interface, @extends, etc.

We also don't need @access that is currently in modules/forum/forum.module (and should be removed -- adds no information that is not in the next line in the function definition line.

Sooooooo....

Basically, the API module can support anything we want to do. (It needs added support for @var, but that's a separate issue which we'll file if we don't already have one -- it's all over core already.)

So the question remains: What do we want to see when we are browsing the code, in a doc header?

Do you like the proposal in #3? api.module will do fine without any doc header on methods that are implementations/overrides, so we can get rid of them if we want to make that the standard. Personally I don't like that idea, because as a doc maintainer it's difficult to tell the difference between method A that is missing doc due to an oversight and method B that is missing doc because it doeesn't need it.

Thoughts?

Can we get this resolved? Please?
:)

jhodgdon’s picture

Also we should add to the standard what @var is used for and that you should put @throws YourExceptionClass if your method throws an exception.

sun’s picture

oh, I wasn't really aware that it's debated whether to have a docblock at all, sorry.

I'd also say we want them - and more or less the same rules for hook implementations can be applied, i.e. "Implements/Overrides ..." and if the function is complex or needs documentation for implementors, then also use a function description.

jhodgdon’s picture

Status: Active » Needs review

OK. Once again, can we get a consensus on adopting this as the standard (#3 with some added explanation on @var and @throws), or else a proposal for a different standard?

Notes:
- Blank line between class declaration and first docblock.
- 3rd person verb for description of class/method/interface (e.g. Represents not Represent)
- For a member variable, use @var to tell what data type the variable is.
- Use @throws if your method can throw an exception. Include the name of the exception class and a brief description of why it might be thrown.

/**
* Represents a prepared statement.
*/
interface DatabaseStatementInterface extends Traversable {

  /**
   * Executes a prepared statement.
   *
   * @param array $args
   *   Array of values to substitute into the query.
   * @param array $options
   *   Array of options for this query.
   *
   * @return
   *   TRUE on success, FALSE on failure.
   */
  public function execute($args = array(), $options = array());
}

/**
* Represents a prepared statement.
*
* Default implementation of DatabaseStatementInterface.
*/
class DatabaseStatementBase extends PDOStatement implements DatabaseStatementInterface {

  /**
   * The database connection object for this statement DatabaseConnection.
   *
   * @var DatabaseConnection
   */
  public $dbh;

  /**
   * Constructs a DatabaseStatementBase object.
   *
   * @param DatabaseConnection $dbh
   *   Database connection object.
   */
  protected function __construct($dbh) {
    // Function body here.
  }

  /**
   * Implements DatabaseStatementInterface::execute().
   */
  public function execute($args = array(), $options = array()) {
    // Function body here.
  }

  /**
   * Returns the foo information.
   *
   * @return object
   *   The foo information as an object.
   *
   * @throws MyFooUndefinedException if the foo is undefined.
   */
  public function getFoo() {
    // Function body here.
  }

  /**
   * Overrides PDOStatement::fetchAssoc().
   */
  public function fetchAssoc() {
    // Call PDOStatement::fetch to fetch the row.
    return $this->fetch(PDO::FETCH_ASSOC);
  }
}
Berdir’s picture

Looks good to me.

What about not requiring but suggesting to document what those overriden methods do? Interface implementations usually just, well, implement what's already described in the interface but overriden methods either extend or change existing behavior so that might need additional explanation. Something like:

  /**
   * Overrides PDOStatement::fetchAssoc().
   *
   * Optional explanation comes here.
   */
  public function fetchAssoc() {
    // Call PDOStatement::fetch to fetch the row.
    return $this->fetch(PDO::FETCH_ASSOC);
  }
sime’s picture

I thought the original at #3 was good enough to go in as a first iteration, so this is even better!

I like what Berdir suggested of course, no harm in encouraging extra documentation.

jhodgdon’s picture

Yes...

IMO, the standard should be like for hook implementations: Minimally just say "implements/extends whatever", and if it needs more clarification, do that. I guess we should add a method that does that.

jhodgdon’s picture

Can we get a couple of votes for or against the proposal in #34 with the addition of #35?
- sime says yes
- I say yes

I would like some input from anyone involved in the DBTNG project, or otherwise interested in doc standards, and hopefully from drumm confirming this is what the API module is expecting... please? This is holding up a number of issues about documenting classes in D7 as we wait to have standards to document them with.

Crell’s picture

The problem with using "Overrides ParentClass::foo()" as the description is that then replaces the real, useful description from the parent class in code assistance in IDEs. So it's really just a distraction for those users.

jhodgdon’s picture

Valid concern (#39, Crell). What would your suggestion be then?

Another concern: there are some users who do not use an IDE, and would find "Overrides ParentClass::foo()." to be useful information to have in there if they are looking at the file in a plain-text editor.

Another concern: I am not sure what the API module is going to do when displaying functions that are overrides. We would like to have a short description to display in a function/method list, and on the method's detail display page and I am not sure right now whether it will pick up the description from the interface/class that is being implemented/overridden.

I do not know whether we can satisfy everyone completely with one solution. What I would like to do is choose the solution that will come closest to satisfying everyone:
- People writing documentation (not too much of a burden, easy to remember/understand).
- Maintainers of documentation (not repeating information in two places, so we shouldn't have to put all the information from an overridden/implemented method on the overriding/implementing method).
- Coders looking at class/method/property doc on api.drupal.org (making sure the API module will parse/display it intelligently)
- Coders using a full-featured IDE
- Coders using a plain-text editor
(I think that's a pretty complete list of the stakeholders)

I would love to see an alternate proposal if anyone has one that will come closer to the proposal above to satisfying everyone. Please? Pretty please?

Berdir’s picture

The only thing I wanted to add is that I find the current way of defining a @throws a bit strange.

   * @throws MyFooUndefinedException if the foo is undefined.

We basically make a sentence of the whole thing, including @throws and the Exception name. This is imho a) not consistent with other things like @params and b) api.module would need to be pretty intelligent to parse that into a useful, complete description sentence.

And when thinking more about it, do we even need to description? If we use an exception in 10 different places, is there any reason to document in 10 times? The reason for throwing the exception should always be the same, if not, then we should use a different exception there IMHO. If you need to know more about the exception, then read the documentation of that exception and api.module could even integrate that into the same page if we really want that.

Just for reference, Java doesn't say anything about a description either: http://java.sun.com/j2se/javadoc/writingdoccomments/#throwstag

Not sure about the Overrides stuff. I'm pretty sure that we can make api.module intelligent enough to integrate the parent/interface documentation but we can't do much about IDE's, which I'm pretty sure will not display the parent documentation unless you work against the parent class/interface and don't care/know about the actually used implementation. This is for example the case with the database layer, you will only see the description of SelectQuery_mysql if you open the file and look at the source code. The IDE and api.module should not care much about that.

jhodgdon’s picture

Good point on the exceptions. I agree that we don't need a description.

Still not sure what to do about overridden/implemented methods...

Crell’s picture

I've sent an email to the PHP-General mailing list to see if they have any useful thoughts here.

Also agreed regarding Exceptions.

lostchord’s picture

This is a variant of a post in #807336: Document thrown exceptions in database layer, it was suggested I post it here instead....

You have, at the minimum, two sets of stakeholders here:

(1) Those who are working with the API code and see the documentation as augmenting what they are seeing in the IDE, and
(2) Those who want to use the API and have absolutely no interest in the code of that API.

For example, everybody doing any coding with Drupal is probably going to the PHP Manual from time to time - or in my case over and over again at present :-) PHP is just a bunch of code, an API if you like, that is used to produce Drupal. Nobody is interested in what that code looks like, they just want to use it. That's stakeholder group (2), they will be reading the API pages.

Then there are the other folk, group (1), who want to change Drupal itself, they want to look at the API in an IDE and have it work magic for them because inheritance and overloading makes life miserable.

I think this discussion is dominated by group (1) and the API pages should be targeting group (2).

I believe you need to get this fundamental issue sorted before you will make much progress here.

cheers

thinkling’s picture

@lostchord, apologies if I'm underestimating you, but reading between the lines I think you may be missing the fact that the online API documentation pages (the ones on api.drupal.org, not the handbook pages) are auto-generated from the same Doxygen comments in the code that folks are discussing above. This whole discussion is about enabling the creation of better documentation.

For the automatic information extraction to work right, it's important to establish a standard way of formatting the comments, which is what this issue discussion is about. This is not about API doc *vs* IDE behavior. It's a given that the outcome will benefit those consulting the API documentation. Of course it's nice if it *also* benefits those coding in IDEs.

If I misunderstood your question, maybe you can explain more directly where you feel API doc is getting shortchanged.

lostchord’s picture

@thinkling, I know exactly how the documentation is derived.

If I were going to create better documentation out of the information embedded in the code I would start with what I consider great documentation and then work out what I need to embed in the code to achieve this. What I see here doesn't seem to be really addressing this directly.

Why not generate examples of the documentation, mockups, kick that around until everybody is satisfied and then, and only then, work out how this needs to be represented in the embedded code comments and what needs to be added to the API module to support it.

That's all.

Berdir’s picture

@44/46: Of course is this *discussion* dominated by group 1, members of group 2 don't look into issues like this in the first place. But I don't think that we ignore group 2, the whole point of this issue is to figure out a way that works best for all groups (there are more than just two, just read #40). Also, I disagree with having good documentation first and then standardize on a way how to document that. Because once we have the standard, we can start to improve documentation parallel and in many different issues and incrementally improve the docs. If we do it as you suggest, then all the documentation needs to be re-worked, re-written and updated every time we change the standards.

Doesn't look like Crell's thread on the php mailing list is getting anywhere, there are just lots of people claiming that he got it all wrong ;) (see http://osdir.com/ml/php-general/2010-05/msg00770.html).

To summarize my point of view:

- When implementing an interface, there is no point in repeating the information, because the interface is the same, only the implementation differs, which is not relevant when you use that interface. You only care about the actual implementation when looking at the source code, so imho, documentation about that can simply be done as inline comments. Additionaly, for most if not all cases, we usually have factory functions, so you do not care which implementation you use and work against the interface. So I'd vote for a simple "Implements ... " as we have it in the example.

- When having a child class which overrides a parent class, then there is usually a reason for doing that, so I guess we can reference the parent implementation and also document in the docblock what this implementation is doing differently but not repeat existing information. Just as I suggested in #35. And when the parent class is abstract and defines abstract methods, then we can document them there and use "Implements... " similiar to interfaces.

- Additionally, we should always use the interface/base class for factory functions, take db_select() for example: http://api.drupal.org/api/function/db_select/7. Instead of SelectQuery, we should document SelectQueryInterface as the return type. Advantage: IDE-autocomplete displays the full documentation of the interface, api.module can make it clickable and point directly to the class (instead of clicking to the class and then the interface)

This gives us the following for the different "readers" (taken from #40):
- People writing documentation: A single place to document the API and small copy&paste-able references which do not need to be updated

- Maintainers of documentation: Same as above imho

- Coders looking at class/method/property doc on api.drupal.org: Documentation of the parent/interface documentation is just a click away, implementation details are either displayed too or displayed as inline comments directly inside the code.

- Coders using a full-featured IDE: See the interface/base class documentation as long as they work against them, which they should. I think instances when you work directly with a specific implementation is rare, and for example, there is a drupal plugin for Netbeans (which is outdated and not really maintained, but someone could change that) which we could enhance to automatically pull-in documentation about the parent class/interface when it discovers a Implements/Overrides or directly through class information.

- Coders using a plain-text editor: Probably use a.d.o most of the time, where they find all the documentation at most 1-2 clicks away or when they look at the source code, get a hint at where to look.

Anyone disagrees? :)

jhodgdon’s picture

#47++

Good point especially about IDEs should be using the interface/base class anyway... although not so much if they do new SelectQuery or something like that? anyway they shouldn't be doing that much in Drupal, should be doing db_query(), right?

So... I guess we need to rework #33, incorporating #35 and #41, so we have something concrete to vote on. And I think we are starting to have some consensus...

Berdir’s picture

Yes, afaik, pretty much every place in Drupal where we use classes has factory functions, which return (to a different degree configurable) implementations against an interface.

An incomplete list (many of these are often not even used directly but only internally, some are missing proper documentation):
- http://api.drupal.org/api/function/drupal_mail_system/7
- http://api.drupal.org/api/function/_cache_get_object/7
- http://api.drupal.org/api/function/file_stream_wrapper_get_instance_by_u...
- http://api.drupal.org/api/function/file_stream_wrapper_get_instance_by_s...
- http://api.drupal.org/api/function/_batch_queue/7
- http://api.drupal.org/api/function/entity_get_controller/7
- http://api.drupal.org/api/function/db_select/7 (and db_query/update/insert/delete/or/and/xor/transaction/....)
- DrupalQueue::get() not yet linkable ;)

No factory function (not counting PHP classes):
- DatabaseTasks, but these are only used in the installer
- FileTransferLocal (used for example in http://api.drupal.org/api/function/update_manager_update_ready_form_subm..., this will (hopefully) not be used by the typical coder :))
- A few more in simpletest/database internals, nothing you are going to touch on a regular basis)

jhodgdon’s picture

We will need to make sure the return values for these are documented in the doxygen, so that IDEs will pick them up correctly, and that we document them as returning the interfaces. Thanks for compiling the list, Berdir!

And the links to classes on api.drupal.org are coming soon, hopefully... drumm and company are working hard on the new version of the API module...

lostchord’s picture

@Berdir:

Of course is this *discussion* dominated by group 1, members of group 2 don't look into issues like this in the first place.

I would consider myself a member of group 2 at present and I'm very interested in this issue because I think the API documentation could do with a bit of improvement. So my interest is selfish and focused (at present) on group 2 requirements. I would suggest that this would probably be the case with most users starting using Drupal with some ideas around coding their own modules. Is this a group you want to nurture?

Apart from different types of users you also have different presentation methods. Print you ignore. The API pages don't have the "Printer friendly version' option and the "everything in a few clicks" approach isn't always appropriate in this case, you may want to consider inline content that can be expanded instead.

Is this sort of issue in scope here?

cheers

Berdir’s picture

Imho it is out of scope.

This issue is not about the quality of the documentation, not even the content at all. It is about defining a common standard of *how* (and not *what*) to write documentation for classes so that all the different readers (be it humans or IDE's or parsers) are able to "understand" it and to ensure a consistency, so that you know when you for example see a "Implements SomeClass::someMethod()" where you have to look.

If you want to improve documentation then check out http://drupal.org/contribute/documentation and start writing ;)

lostchord’s picture

#52

I'm not sure you can contemplate a "How" without some pretty complete concept of "What". You previously mentioned standards and what a pain it is when you change them. You bet! Real painful. Which is why you probably want to make sure you understand all the What's so that you can be sure your How's will not need to be changed the following morning.

In terms of improving documentation I think that the Documentation Team is probably a better starting place for canvasing the fundamental issues that exist with the documentation today.

Crell’s picture

So I have reached a couple of important conclusions here.

1) PHP-General is mostly for trolling.
2) IDE authors are morons.
3) PHP sucks.

These likely don't come as a surprise to anyone, but I figured I'd mention it anyway. *sigh*

The only useful suggestion to come out of that thread was this:
http://osdir.com/ml/php-general/2010-05/msg00797.html

Which points to this bit of PHPDoc:
http://manual.phpdoc.org/HTMLSmartyConverter/HandS/phpDocumentor/tutoria...

Of course, that is for inheriting the longdesk, which is of all the parts of the docblock the one we care about the least here. Arguably we could add another tag of our own to do something else, but IDEs still wouldn't read that.

I think Berdir's suggestion to handle IDEs with "well that's just one more reason to always always always use an interface" is the best we're going to be able to do. There's simply nothing else that I have been able to find that any of the major IDEs will do.

I don't like the "Implements Foo::bar()" syntax, for a couple of reasons. One, we already use "Implements" for hooks in a few thousand places. Rightly or wrongly, that's going to be confusing since hooks are not interfaces. Two, I can see that being harder to parse.

Since we have our own parser though, and if we ever fully move to PHPDoc (as I believe we should) it is extensible, we can define our own documentation tag for that. Something like

class Foo extends Bar implements Baz {

/**
* Full docblock here.
*/
function a() { }

/**
* @implement Baz
*/
function b($x, $y) { }

/**
* @override Bar
*/
function c($x, $y) { }
}

And then api.module can just detect @implement and @override and pull in documentation as necessary. (Knowing which method to pull from is trivial at that point, since it has to be the one with the same name.)

lostchord: This sort of documentation is already well standardized. PHPDoc and Doxygen and JavaDoc are all very widely used documentation systems by thousands of projects. All we're trying to do in this thread is fill in a few gaps in the existing standards for the technology. Drupal is already a fairly well documented system, so we already know the "What". This is just edge cases for the How.

The only reason we'd have to revisit the entirety of How from the ground up would be if we wanted to throw out the entire Doxygen/PHPDoc concept and start from scratch, which is seriously not in scope. :-) This is a well-understood problem space already.

lostchord’s picture

@Crell

This sort of documentation is already well standardized.

But you have chosen to implement your own subset of Doxygen.

Drupal is already a fairly well documented system

The documentation is improving, well documented is drawing a long bow.

Documentation that relies on developers is, has always been, may well continue to be, an issue. There is a lack of focus there because, particularly in the OSS environment, there is limited incentive to get it right. If I don't do the documentation right I can write a book, sell support,...whatever.

Embedding documentation in the source code is a two edged sword. Who is responsible for it? What goes in the source code and what goes in the Handbooks, is the same process used to control content on each and ensure synchronisation... are these broader issues being considered? Are the necessary controls placed around source code completely appropriate where documentation is concerned particularly if you want to encourage community participation in documentation (which you have to do if you want to improve).

Documentation tends to be the poor citizen in this environment because everybody involved (well nearly everybody) is doing it as a hobby. They have 'no skin in the game'.

YMMV :-)

cheers

Crell’s picture

lostchord: What you're debating is extremely off topic for this thread. You're still talking grand plans and content changes to documentation. The *only* thing relevant in this thread is how we want to document inheritance and interface usage within the currently existing inline documentation framework. Anything else is off topic and should be moved elsewhere. Please do not derail this issue.

jhodgdon’s picture

OK

So here is yet another try at getting a standard approved.... This is basically the same as the last one, incorporating a few updates suggested in comments.

Notes:
- Blank line between class declaration and first docblock.
- 3rd person verb for description of class/method/interface (e.g. Represents not Represent)
- For a member variable, use @var to tell what data type the variable is.
- Use @throws if your method can throw an exception, followed by the name of the exception class. If the exception class is not specific enough to explain why the exception will be thrown, you should probably define a new exception class.
- Crell: we don't want to introduce a new tag @implements now that the API module will have to handle.
- [EDIT: ADDED] Make sure when documenting function return values to use the most general class/interface possible. E.g., document the return value of db_select() to be a SelectQuery, not a particular class that implements SelectQuery.
- [EDIT: CORRECTION] Make sure when documenting function return values to use the most general class/interface possible. E.g., document the return value of db_select() to be a SelectQueryInterface, not a particular class that implements SelectQuery.

/**
* Represents a prepared statement.
*/
interface DatabaseStatementInterface extends Traversable {

  /**
   * Executes a prepared statement.
   *
   * @param array $args
   *   Array of values to substitute into the query.
   * @param array $options
   *   Array of options for this query.
   *
   * @return
   *   TRUE on success, FALSE on failure.
   */
  public function execute($args = array(), $options = array());
}

/**
* Represents a prepared statement.
*
* Default implementation of DatabaseStatementInterface.
*/
class DatabaseStatementBase extends PDOStatement implements DatabaseStatementInterface {

  /**
   * The database connection object for this statement DatabaseConnection.
   *
   * @var DatabaseConnection
   */
  public $dbh;

  /**
   * Constructs a DatabaseStatementBase object.
   *
   * @param DatabaseConnection $dbh
   *   Database connection object.
   */
  protected function __construct($dbh) {
    // Function body here.
  }

  /**
   * Implements DatabaseStatementInterface::execute().
   *
   * Optional explanation of the specifics of this implementation goes here.
   */
  public function execute($args = array(), $options = array()) {
    // Function body here.
  }

  /**
   * Returns the foo information.
   *
   * @return object
   *   The foo information as an object.
   *
   * @throws MyFooUndefinedException
   */
  public function getFoo() {
    // Function body here.
  }

  /**
   * Overrides PDOStatement::fetchAssoc().
   *
   * Optional explanation of the specifics of this override goes here.
  */
  public function fetchAssoc() {
    // Call PDOStatement::fetch to fetch the row.
    return $this->fetch(PDO::FETCH_ASSOC);
  }
}
rfay’s picture

+1 - and then set aspilicious on the prowl to enforce it all.

aspilicious’s picture

I agree with the proposed standards :D...

Great job jhodgdon!

Berdir’s picture

Looks good to me too!

I don't really get Crell's reason in #54 regarding not using Implements because we already use it for hooks. Using a @tag in the first line looks strange to me and is a) totally against all other coding standards we have (first sentence stuff) and b) we do not need a tag because api.module can detect implemented/overriden methods simply by parsing the class definition (class ChildClass extends ParentClass implements AnInterface). The "Implements/Overrides .. " text is imho just for a human reader.

jhodgdon’s picture

I would like to wait to adopt this until we verify that the new API module code (6.x-dev version) can work well with this. I have asked drumm to comment, but if anyone else wants to test or verify, that would be lovely too.

drumm’s picture

#54 on @implement and @override: this is just repeating what we know from code. The dev version of API module actually already shows if class members override or inherit from their parent classes, on class pages. I think I broke it recently, but http://api.scratch.drupal.org/api/Drupal/includes--database--sqlite--dat... shows the general idea. Documentation should not repeat what we already know from the structure of the code.

http://api.scratch.drupal.org/ is the staging site for the new stuff. Things from #57 should already be fully implemented. Please file issues for what is wrong.

chx’s picture

I checked the http://api.scratch.drupal.org/ site and while awesome, can't we will in the missing class documentation from the interface?

jhodgdon’s picture

What are you saying chx? I'm not following...

mikey_p’s picture

jhogdon, I think what chx is referring to is what I outlined in #710774-3: Ensure all class-related items are parsed. I'm pretty sure that this should be filed against API module.

For instance the documentation from http://api.scratch.drupal.org/api/Drupal/includes--database--query.inc/f... should be shown on http://api.scratch.drupal.org/api/Drupal/includes--database--query.inc/f....

jhodgdon’s picture

Yes, that's API module material.

drumm’s picture

jhodgdon’s picture

OK...

So can we adopt #57 as our standard?

It looks like drumm, rfay, aspilicious, and Berdir agree.

chx, Crell, anyone else?

sun’s picture

Nitpick on #57, since you asked:

- [EDIT: ADDED] Make sure when documenting function return values to use the most general class/interface possible. E.g., document the return value of db_select() to be a SelectQuery, not a particular class that implements SelectQuery.

s/SelectQuery/SelectQueryInterface/ -- if I remember latest discussions elsewhere correctly.

jhodgdon’s picture

Perfect. I will edit #57 accordingly.

Crell’s picture

I still think the double-use of "Implements" will be confusing (we switched to that for hooks, too, a while back), but not so much that I am going to block it.

PHP sucks, this is the best we can do for now, I guess. The rest is issues for api.module until we can switch to phpDocumentor.

jhodgdon’s picture

Status: Needs review » Fixed

OK, this looks like consensus to me. I've added it to:
http://drupal.org/node/1354#classes

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.