Documenter is a library (more of an extension or wrapper) based on phpDocumentor, which, as of this writing, is the more popular base library for interacting with inline documentation for PHP projects.
There are a multitude of generators available for creating documentation sites for PHP projects. Many of those generate static sites (HTML or other files) for presenting on the web. This makes sense for two primary reasons:
- content is static (the project's PHP files don't typically change once captured) and
- performance (large projects can contain hundreds or even throusands of files).
However, when examining projects at 8fold (and a few others), we found these two considerations no longer carrying the weight they once would have. As PHP projects become more modular, the number of files to capture documentation for is becoming less and less. Further, PHP and its related Zend Framework are actually pretty fast. Finally, various modern development techniques can also reduce the load put on the server to generate the documentation. (See Performance section for more details.)
At 8fold, we also found limitations with the static site generators, which inspired us to try something different.
Add Documenter to a PHP project and deliver the documentation via web-based APIs. Add Documenter to a dynamic site and integrate it seemlessly (no need to switch from dynamic content delivery to static content delivery). Change your return strings or template files without having to do anything else to update all project versions to the new look and feel.
$ composer require 8fold/documenter-php
Or add the following to the require portion of your composer file and run composer install
or composer update
:
"8fold/documenter-php": "*"
Recommend adding this to your PSR-4 declaration:
"Eightfold\\DocumenterPhp\\": "vendor/8fold/documenter-php/src/"
Documenter also uses the following:
The main entry class for Documenter is, well, the Documenter class found in /src
; see documentation what information is required. Once initialized, you should be able to traverse things pretty easily. (In relative terms.)
If at any point you get stuck, please either update the documentatin, or let us know, and we will do our best to improve the experience.
- Element: A piece of code that can have associated DocBlock.
- Object: An element with an independent scope.
- Symbol: An element with a dependent scope.
For example, the following are all "objects":
<?php
// Variable
$hello = 12;
// Function
function hello($int) { return $int; }
// Class_
class Hello {}
// Trait_
trait Hello {}
// Interface_
interface Hello {}
Further, for symbols; using the class Hello
from above:
<?php
// Class_
class Hello {
// Property
$hello = 12;
// Method
function hello($int) { return $int; }
}
All of the above are representations of elements.
DocBlocks are the main way to document your code and make it ready for Documenter. For PHP a DocBlock appears between a forward slash followed by two asterisks (/**) and single asterisk followed by a forward slash (*/). Further, they appear just above the element being documented.
/**
* This is the short description of the DocBlock.
*
* The long description begins one empty line (paragraph) below the short description.
*/
class HelloWorld
{
/**
* Short description
*/
private function print()
{
// Comments such as these do not count.
}
}
Documenter is not all that opinionated when it comes to the way you write your DocBlocks; therefore, you can read the phpDocumentor documentation to get a handle on writing documentation in your code.
Having said that, the following are some things to consider and be aware of when working with Documenter.
@category: phpDocumentor has deprecated use of the @category
tag. We understand and agree with the desire to deprecate this tag given what it was initially designed to do. However, semantically, it is the most appropriate tag name for grouping various elements to generate a site; therefore, Documenter does take advantage of this tag for the purposes of bucketing methods, properties, classes, traits, and so on.
Note: Think of categories like sections on a page, but asking you to update all your @category
tags to @section
seems like a lot to ask all things considered.
Return types: If you have a method that returns an instance of an object within your project, you can create a more robust user experience by documenting this type as the full class namespace preceded with a backslash.
// We have a class with a full name of: Hello\World\Class
/**
* @return \Hello\World\Class
*/
public function instance() {}
When Documenter returns the tring for the type hint, the string will be "Class" indicating it is a class within the current project. Further, by setting the withLink
parameter to true
when getting the display string, an anchor to the URL of the object will also be present.
<a href="/[project-slug]/[version-slug]/hello-world/class">Class</a>
For classes that are not in the scope of the project, Documenter still only returns the class name (without the name space), but wraps the name in square brackets ([]).
Something\Outside\The\Project\Space\SomeClass
Becomes:
[SomeClass]
The important thing is the backslash at the beginning of the namespace. Further, this functionality applies to the parents of classes.
use Hello\World\Class
use Something\Outside\The\Project\Space\SomeClass
class MyLocalClass extends Class
{
}
class MyExternalClass extends SomeClass
{
}
The result for getting the display string of the parents would be the same as the previous outputs.
Documenter is to designed to help you generate a website; therefore, all documentable objects can generate a URL. This URL is for generating links only and does not act as a routes list nor a routes generator. Having said that, if you are using a framework that allows you to generate routes with properties, you can use the following list as a starter.
Having said that, you do not need to be building a website to take advantage of Documenter.
A note on what gets a single view URL:
To help create what we find to be a better user experience, the default URL generation is that any documentable Project Object (Class_, Trait_, Interface_, Property, ClassMethod) can have its own URL. This includes:
- classes,
- traits,
- interfaces,
- properties, and
- methods
Note: You are not required to separate your documentation site out in this manner; however, keep this in mind when using Documenter.
A note on namespaces:
- Because PHP allows for multiple namespaces within the same project, it was decided that including the namespace in the URL was the easiest way to allow for two objects with the same name but different namespaces to exist in the same project documentation.
- Even though namespaces are considered to be somewhat hierarchical, the namespace generated for the URL does not create multiple levels, which should make it easier for developers and site users.
/{project-slug}/{project-version-slug}
This is the base URL generated by a given project version.
/{project-slug}/{project-version-slug}/{object-namespace}/{functions or properties}/{project-object-slug}
This is the url for viewing a specific Method or Property not "owned" by another Project Object. project-object-slug
is the name
of the object converted to a slug.
Note: Most of the projects we work on do not have functions or methods that exist outside a Class_, Trait_, or Interface_. Therefore, namespace may not be a necessary consideration. Put this analysis in the TODO column.
/{project-slug}/{project-version-slug}/{object-namespace}/{classes, traits, or interfaces}/{project-object-slug}
This is the url for viewing a specific Class_, Trait_, or Interface_.
/{project-slug}/{project-version-slug}/{object-namespace}/{classes, traits, or interfaces}/{project-object-slug}/{methods or properties}/{project-object-slug}
This is the url for viewing a specific ClassMethod or Property.
Note: Documenter objects do not generate the following URLs; however, they become possibilities through the creation of the above. (A user could remove the project-object-slug
of the URL in their browser and try to view that page, for example.) Therefore, if you are integrating Documenter into a PHP framework that has a route provider, you may want to consider creating pages for these as well to improve the user experience of the site.
/{project-slug}
This is a prefix URL generted to allow creating a list of versions for a project.
/{project-slug}/{project-version-slug}/{object-namespace}
This is a prefix URL to allow creating a list of Project Objects within a given Namespace.
/{project-slug}/{project-version-slug}/{object-namespace}/{project-object-name}
This is a prefix URL to allow creating a list of Class_, Trait_, Interface_, Method, and Property objcts found in the files within the project. project-object-name
will be one of the following strings, listed in respective order to the type of object instantiated:
- classes
- traits
- interfaces
- functions
- properties
/{project-slug}/{project-version-slug}/{object-namespace}/{classes, traits, or interfaces}/{project-object-slug}/{methods or properties}
This is a prefix URL to all the creation of apage lsiting all the Method or Property Project Objects used by a single Class_, Trait_, or Interface_.
Documenter is designed to only instantiate or calculate when absolutely necessary (lazy loading). Documenter is designed to hold onto objects and values once they have been instantiated or calculated (caching).
Documenter has not been performance tested; if performance in live applications ever becomes a noticeable issue, we will do so. Having said that, it is estimated that the longest operation in Documenter is going to be in setting up the initial array of files for a Project.