gossi/docblock
gossi/docblock is a lightweight PHP library for parsing and generating PHP docblocks. It offers a clean API to read descriptions, tags, and annotations, and to build well-formatted docblocks programmatically—useful for code generators, tooling, and static analysis workflows.
Install with composer require gossi/docblock and verify the PHP constraint in the package's composer.json before committing — the last tagged release is from September 2021, so on PHP 8.2+ you'll want to run it through your test suite first rather than trusting it blindly.
Start by reading the two classes that matter: the parser (turns a raw /** ... */ string into a structured DocBlock object) and the generator (serializes that object back to text). The README and src/ are small enough to skim in ten minutes. Ignore the test fixtures on the first pass.
Your first real use case in a Laravel app is almost always model docblock generation. Eloquent models accumulate @property, @method, and @mixin tags that IDE and static-analysis tooling depend on. A quick win is an Artisan command that reflects over a model, reads its table schema via Schema::getColumns(), builds a DocBlock object with @property tags, and writes it back above the class. That single command demonstrates the full parse → mutate → generate → persist loop you'll reuse everywhere else.
Service-provider binding. Wrap the parser/generator in a small DocblockService and bind it as a singleton. This gives you one place to configure formatting (indentation, tag ordering) and one place to swap the implementation later if maintenance becomes a problem.
Artisan codegen commands. The natural home for this package is app/Console/Commands. Typical commands:
models:docblock — regenerate @property annotations from the schema.routes:docblock — inject @route or OpenAPI-ish tags into controller methods by reading Route::getRoutes().docs:sync — parse all docblocks under app/ and emit a JSON or Markdown index for internal docs.Structure each command as: collect targets via ReflectionClass/ReflectionMethod, call getDocComment(), parse, mutate the tag array, generate, then write back with a Finder + file_put_contents. Keep the "write" step behind a --dry-run flag.
Reflection-first input. ReflectionClass::getDocComment() returns false when there's no docblock, so always guard before handing the string to the parser. When the comment exists, strip the leading /** and trailing */ only if the parser expects raw content — check whether the package wants the delimiters included or not, because that differs between docblock libraries and getting it wrong produces mangled output.
Round-trip mutation. Prefer parse → modify the tag collection → regenerate over string replacement. Regex-editing docblocks is how you end up with duplicated @property lines. Treat the generated output as the source of truth and let the package format it.
CI drift check. Add a docblock:check command to your pipeline: run the generator in dry-run mode and fail if any file would change. This keeps annotations from rotting and is the single highest-value integration for a team.
Test fixtures. Keep a tests/fixtures/docblocks/ directory of representative inputs (multiline descriptions, tags with array values, no tags at all). Snapshot the generated output so upgrade regressions are obvious.
composer.json ("gossi/docblock": "x.y.z") and write a thin adapter interface so you can swap to phpdocumentor/reflection-docblock or phpstan/phpdoc-parser without touching command code.@param columns will be reflowed. Run Pint after generation if you care about consistency, and be aware Pint may fight the generator on tag alignment.@deprecated note to make sure round-tripping preserves intent.--dry-run, log a unified diff for changed files. Docblock regeneration touching dozens of models in one commit is easy to review when the diff is printed, and terrifying when it isn't.docblock:check CI gate as non-negotiable once you adopt this.How can I help you explore Laravel packages today?