Turn PHP Attributes Into Docs With Signal
Composer Pacakge PHP #PHP #PHP Attributes #Documentation #Laravel Packages #Open Source #Developer Tools

Turn PHP Attributes Into Docs With Signal

3 min read Mohamed Said Mohamed Said

What Is Signal?

Signal is an open-source PHP library by Steve McDougall that turns native PHP 8.x attributes into living documentation. Instead of maintaining a separate wiki or API reference that drifts out of date, you annotate your classes and methods directly, run one CLI command, and get back Markdown for humans and JSON for tooling. It requires PHP 8.5 and Symfony Console, and is distributed under the MIT license.

Three Groups of Attributes

Signal ships 24 attributes organised into three logical groups.

1. Labelling What a Class Is

Thirteen attributes describe the architectural role of a class: #[Module], #[Service], #[Repository], #[Action], #[Controller], #[Event], #[Listener], #[Middleware], #[Job], #[Command], #[Query], #[Aggregate], and #[ValueObject]. Each accepts an optional description and a tags array.

use JustSteveKing\Signal\Attributes\Service;

#[Service(
    description: 'Issues and revokes API tokens for authenticated users',
    tags: ['auth', 'tokens'],
)]
final class TokenService
{
    // ...
}

The generator groups output by these types, so every controller lands in one section and every service in another.

2. Recording Relationships and Status

A second group documents how a class connects to the rest of the system. #[DependsOn] records a collaborator, #[ListensTo] ties a listener to an event, and #[Deprecated] / #[Internal] flag classes that callers should treat with care.

#[Listener(description: 'Sends a welcome email after registration')]
#[ListensTo(event: UserRegistered::class)]
#[DependsOn(class: MailService::class)]
final class SendWelcomeEmail
{
    // ...
}

This is the kind of relationship detail that usually lives only in someone's head or in a diagram nobody updates.

3. Documenting Methods

The third group targets individual methods. #[Route] records an HTTP method and path, #[Authorize] notes the required ability, #[Validates] captures field-level rules, and #[Cached] records a TTL. Three more attributes surface behaviour invisible in a method signature: #[Emits] for dispatched events, #[Throws] for exceptions, and #[SideEffect] for observable work like charging a card or writing to a queue.

#[Route(method: 'POST', path: '/api/subscriptions', description: 'Start a subscription')]
#[Authorize(ability: 'subscriptions.create')]
#[Validates(field: 'plan', rules: 'required|in:monthly,yearly')]
#[Emits(event: 'SubscriptionStarted')]
#[SideEffect(description: 'Charges the customer through the payment gateway', tags: ['billing'])]
#[Throws(exception: PaymentFailedException::class, description: 'If the gateway rejects the charge')]
public function store(Request $request): JsonResponse
{
    // ...
}

#[SideEffect] and #[Throws] are particularly valuable — they document facts a return type alone cannot convey.

Configuration and Output

Signal reads a signal.json file at the project root:

{
    "input": "src/",
    "output": {
        "format": ["markdown", "json"],
        "path": "docs/"
    },
    "exclude": [
        "src/Attributes/"
    ]
}

Then generate your docs with a single command:

php vendor/bin/signal generate

The Markdown output includes a table of contents organised by class type. The JSON output carries the same metadata in a machine-readable form, making it a useful starting point for generating OpenAPI descriptions or feeding an internal service catalogue.

Installation

composer require juststeveking/signal

Key Takeaways

  • Signal uses native PHP attributes — no docblock parsing, no external annotation syntax.
  • 24 attributes cover class roles, inter-class relationships, and method-level behaviour.
  • Outputs both Markdown (human-readable) and JSON (machine-readable) from one command.
  • Keeping docs next to code means they update when the code updates, reducing documentation drift.
  • Requires PHP 8.5 and Symfony Console; MIT licensed.
  • The JSON output can seed OpenAPI specs or internal service catalogues.

Source: Turn PHP Attributes Into Docs With Signal — Laravel News

Found this useful?

Frequently Asked Questions

3 questions
Q01 What PHP version does Signal require?
Signal requires PHP 8.5 and Symfony Console. It is distributed under the MIT license.
Q02 What output formats does Signal produce?
Signal generates both Markdown (organised by class type with a table of contents) and JSON (machine-readable metadata suitable for OpenAPI generation or service catalogues).
Q03 How do you run Signal to generate documentation?
After adding a signal.json configuration file to your project root, run `php vendor/bin/signal generate`. Signal scans the configured input directory and writes docs to the configured output path.

Continue reading

More Articles

View all