theseer/phpdox
phpDox is a PHP documentation generator that builds API docs from your source code using reflection, tokens, and optional PHPDoc. It produces structured HTML output and integrates with PHPUnit coverage, offering configurable builds for libraries and apps.
Installation
composer require theseer/phpdox --dev
Add to composer.json under require-dev to ensure it’s only installed in development.
Basic Configuration
Create a phpdox.xml config file in your project root (or use the default via CLI):
<?xml version="1.0" encoding="UTF-8"?>
<phpdox>
<source>
<directory>src</directory>
</source>
<output>
<directory>docs/api</directory>
</output>
</phpdox>
First Run Generate docs from the command line:
vendor/bin/phpdox generate
Outputs HTML docs to docs/api by default.
Where to Look First
vendor/bin/phpdox --help for available commands.vendor/theseer/phpdox/resources/phpdox.xml for default settings.vendor/theseer/phpdox/resources/xslt/ for customization hooks.CI/CD Integration
Add to .github/workflows/docs.yml:
- name: Generate Docs
run: vendor/bin/phpdox generate
Push docs to a gh-pages branch or deploy via Netlify/GitHub Pages.
Laravel-Specific Setup
vendor/ and tests/ from source:
<source>
<directory>app</directory>
<directory>config</directory>
<exclude>*/tests/*</exclude>
</source>
bootstrap/app.php for autoloading (no extra config needed).Template Customization
Override default XSLT templates by copying vendor/theseer/phpdox/resources/xslt/ to resources/views/phpdox/ and updating paths in phpdox.xml:
<xslt>
<directory>resources/views/phpdox/xslt</directory>
</xslt>
Dynamic Documentation
Generate docs per-module by splitting <source> tags:
<source>
<directory>app/Http/Controllers</directory>
<name>API Controllers</name>
</source>
Laravel Artisan Command
Create a custom command (app/Console/Commands/GenerateDocs.php) to wrap phpdox with Laravel’s logging:
public function handle()
{
$this->info('Generating API documentation...');
$exitCode = Artisan::call('phpdox:generate');
if ($exitCode !== 0) $this->error('Failed to generate docs.');
}
Register in app/Console/Kernel.php and call via php artisan docs:generate.
Markdown Output
Use the markdown output format for easier GitHub/GitLab integration:
<output>
<format>markdown</format>
<directory>docs/markdown</directory>
</output>
Deprecated Package
composer.json:
"config": {
"platform": {
"php": "7.4"
}
}
DocBlock Parsing Quirks
@throws tags without exceptions may cause errors. Validate with:
vendor/bin/phpdox validate
@mixin or @method from Blade templates by excluding directories:
<exclude>resources/views/*</exclude>
XSLT Caching Issues
rm -rf docs/api/.cache
Performance
php -d memory_limit=2G vendor/bin/phpdox generate
Verbose Output
Enable debug mode in phpdox.xml:
<debug>true</debug>
Or via CLI:
vendor/bin/phpdox generate --debug
Log File Redirect output to a file for CI/CD debugging:
vendor/bin/phpdox generate > docs/generate.log 2>&1
Custom XSLT Filters Extend templates to highlight Laravel-specific elements (e.g., route annotations):
<!-- resources/views/phpdox/xslt/class.xsl -->
<xsl:template match="annotation[@name='route']">
<div class="laravel-route">
<strong>Route:</strong> <code><xsl:value-of select="."/></code>
</div>
</xsl:template>
Pre/Post-Generate Hooks
Use Laravel’s finished event to process docs after generation:
// app/Providers/AppServiceProvider.php
public function boot()
{
if ($this->app->runningInConsole()) {
Artisan::command('phpdox:generate')->listen(function () {
// Post-process (e.g., deploy to S3)
});
}
}
Dynamic Source Filtering
Exclude files dynamically via a custom SourceFilter class (extend phpDox\Source\SourceFilter). Example:
class LaravelSourceFilter extends \phpDox\Source\SourceFilter
{
public function filter(\SplFileInfo $file)
{
return !str_contains($file->getPathname(), 'vendor/laravel/framework');
}
}
Register in phpdox.xml:
<sourceFilter>App\Filters\LaravelSourceFilter</sourceFilter>
Integration with Laravel Scout Auto-generate docs for search indexes by parsing the output XML:
$xml = simplexml_load_file('docs/api/phpdox.xml');
foreach ($xml->classes->class as $class) {
Scout::index($class->name, ['content' => $class->description]);
}
How can I help you explore Laravel packages today?