Missing DocBlock Analyzer
| Analyzer ID | Category | Severity | Time To Fix |
|---|---|---|---|
missing-docblock | 💻 Code Quality | Low | 15 minutes |
What This Checks
- Detects public methods missing PHPDoc comments
- Requires
@paramtags for parameters with generic types (array, iterable, object, mixed, callable) or no type hints - Requires
@returntag for generic return types (array, mixed, iterable, callable, object) or unions containing them, not needed for scalars (void, string, int, bool, float), concrete class names, or unions of concrete classes - Requires
@throwstags for exceptions (when applicable) - Excludes simple getter/setter methods (get*, set*, is*, has*)
- Reports exact file location and line number of each issue
Follows PSR-12 / PSR-5 conventions: @param and @return tags are redundant for non-generic native types but required for generic types to specify their structure.
Why It Matters
- Code documentation: DocBlocks explain what methods do and how to use them
- IDE support: IDEs use DocBlocks for autocomplete and type hints
- API documentation: DocBlocks generate API documentation automatically
- Team collaboration: New team members understand code faster
- Type safety: DocBlocks help catch type mismatches
- Maintenance: Well-documented code is easier to modify
- Best practices: PSR-5 standardizes DocBlock format
- Code quality: Documentation is a sign of professional code
How to Fix
Quick Fix (5 minutes)
Add basic DocBlock to public methods:
// ❌ BAD - Missing DocBlock
public function calculateTotal($items)
{
return array_sum(array_column($items, 'price'));
}
// ✅ GOOD - DocBlock with generic type documentation
/**
* Calculate the total price of items.
*
* @param array<int, array{price: float}> $items Array of items with price field
*/
public function calculateTotal(array $items): float
{
return array_sum(array_column($items, 'price'));
}Note: The @return float tag is omitted because float is a scalar type (self-documenting). The @param tag is required because array is a generic type that needs structure specification.
Proper Fix (15 minutes)
1: Complete DocBlock with Parameters
// ❌ BAD - Missing or incomplete DocBlock
public function processOrder(Order $order, User $user, bool $sendEmail)
{
// Implementation
}
// ✅ GOOD - Complete DocBlock (class types documented, scalar types omitted)
/**
* Process an order for a user.
*
* @param \App\Models\Order $order The order to process
* @param \App\Models\User $user The user placing the order
* @return \App\Models\Order
* @throws \App\Exceptions\InvalidOrderException
* @throws \App\Exceptions\PaymentFailedException
*/
public function processOrder(Order $order, User $user, bool $sendEmail): Order
{
// Implementation
}Note: The bool $sendEmail parameter doesn't need a @param tag because bool is a scalar type (self-documenting). If you want to document what it does, you can optionally include it, but it's not required by this analyzer.
2: Document Generic Return Types
// ❌ BAD - Missing return documentation for Collection (generic type)
public function getUserOrders(int $userId)
{
return User::find($userId)->orders;
}
// ✅ GOOD - Document generic collection return type
/**
* Get all orders for a user.
*
* @return \Illuminate\Database\Eloquent\Collection<\App\Models\Order>
*/
public function getUserOrders(int $userId)
{
return User::find($userId)->orders;
}Note: The int $userId parameter doesn't need a @param tag because int is a scalar type (self-documenting). The @return tag IS required because Collection is a generic type that needs to specify what it contains.
3: Document Exceptions
// ❌ BAD - Missing exception documentation
public function chargePayment(Order $order, float $amount)
{
if ($amount <= 0) {
throw new InvalidAmountException();
}
if (!$order->canBeCharged()) {
throw new PaymentFailedException();
}
// Charge payment
}
// ✅ GOOD - Document all exceptions (class param and exceptions only)
/**
* Charge a payment for an order.
*
* @param \App\Models\Order $order The order to charge
* @throws \App\Exceptions\InvalidAmountException When amount is invalid
* @throws \App\Exceptions\PaymentFailedException When payment cannot be processed
*/
public function chargePayment(Order $order, float $amount): void
{
if ($amount <= 0) {
throw new InvalidAmountException();
}
if (!$order->canBeCharged()) {
throw new PaymentFailedException();
}
// Charge payment
}Note: Both float $amount and : void don't need documentation because they're scalar types (self-documenting).
4: Document Complex Parameters
// ❌ BAD - Missing documentation for array parameter (generic type)
public function searchUsers(array $filters, int $limit = 10)
{
// Implementation
}
// ✅ GOOD - Document array structure and generic return type
/**
* Search users with filters.
*
* @param array<string, mixed> $filters Search filters (e.g., ['name' => 'John', 'status' => 'active'])
* @return \Illuminate\Database\Eloquent\Collection<\App\Models\User>
*/
public function searchUsers(array $filters, int $limit = 10)
{
// Implementation
}Note: The int $limit parameter doesn't need a @param tag because int is a scalar type. The array $filters parameter DOES need documentation because array is a generic type that needs structure specification.
5: Document Nullable Class Returns
// ❌ BAD - Missing documentation for nullable class return
public function findUserByEmail(string $email)
{
return User::where('email', $email)->first();
}
// ✅ GOOD - Document nullable class return type
/**
* Find a user by email address.
*
* @return \App\Models\User|null
*/
public function findUserByEmail(string $email): ?User
{
return User::where('email', $email)->first();
}Note: The string $email parameter doesn't need a @param tag because string is a scalar type. The @return tag is optional for concrete class names (?User is self-documenting). Including it (as shown) is encouraged for readability but will not be flagged if omitted.
6: Union Types of Concrete Classes
// ✅ GOOD - No @return needed, union is fully self-documenting
/**
* Handle the request.
*/
public function handle(): Response|JsonResponse
{
return response()->json([]);
}
// ❌ BAD - @return required because array is a generic type needing shape documentation
/** Doc */
public function search(): string|array
{
return [];
}
// ✅ GOOD - @return documents the array shape
/**
* Search for results.
*
* @return string|array<int, string>
*/
public function search(): string|array
{
return [];
}Note: A PHP 8 union type of concrete classes (e.g., Response|JsonResponse) is fully enforced by the runtime, so @return adds no information. A union containing a generic type (e.g., string|array) still requires @return to document the array shape. Adding a redundant @return to a concrete union would also conflict with Laravel Pint, which strips it as superfluous via the no_superfluous_phpdoc_tags rule.
7: Document Array Shapes
// ❌ BAD - Missing documentation for array return (generic type)
public function getUserStats(int $userId): array
{
return [
'total_orders' => 10,
'total_spent' => 1000.00,
'last_order_date' => '2024-01-15',
];
}
// ✅ GOOD - Document array shape with precise structure
/**
* Get user statistics.
*
* @return array{total_orders: int, total_spent: float, last_order_date: string|null}
*/
public function getUserStats(int $userId): array
{
return [
'total_orders' => 10,
'total_spent' => 1000.00,
'last_order_date' => '2024-01-15',
];
}Note: The int $userId parameter doesn't need a @param tag because int is a scalar type. The @return tag IS required because array is a generic type that needs its shape documented.
References
- PSR-12 Coding Style Guide - Extended coding style standard (supersedes PSR-2)
- PSR-5 PHPDoc Standard - PHPDoc documentation standard
- PHP DocBlock Documentation - Complete DocBlock guide
- PHPDoc Types - Type annotation reference
Related Analyzers
- Naming Convention Analyzer - Validates naming standards
- Method Length Analyzer - Detects methods that are too long
- Commented Code Analyzer - Detects commented-out code