code quality and tooling
Comments and Docblocks
Comments and docblocks are tools for explaining code, but they solve different problems. A normal comment explains a decision in the code. A docblock describes a symbol in a structured way that humans and tools can read.
Good PHP code should not need comments for every line. Clear names, small functions, and native types should do most of the work. Comments are useful when the reason behind the code is not obvious from the code itself.
Avoid comments that repeat the code
This comment adds noise because the code already says what happens.
<?php
declare(strict_types=1);
// Add the price to the total.
$total += $price;
The next version is better because the comment explains the business reason.
<?php
declare(strict_types=1);
// Gift cards are excluded because finance reports them separately.
if ($productType !== 'gift_card') {
$total += $price;
}
Use comments to explain "why", not to narrate obvious syntax.
Native types come first
If PHP can express the type directly, use the language before reaching for a docblock.
<?php
declare(strict_types=1);
function formatMoney(int $pennies): string
{
return 'GBP ' . number_format($pennies / 100, 2);
}
This function does not need @param int and @return string because the signature already says that.
Docblocks help with array shapes
PHP can type a parameter as array, but it cannot fully describe the keys and value types in the function signature. PHPDoc can add that missing detail for readers and static analysis tools.
<?php
declare(strict_types=1);
/**
* @param array{name: string, price: int} $product
*/
function reportLine(array $product): string
{
return $product['name'] . ': GBP ' . number_format($product['price'] / 100, 2);
}
echo reportLine(['name' => 'Notebook', 'price' => 499]);
// Prints:
// Notebook: GBP 4.99
The docblock explains the expected array shape. That is much more useful than a generic @param array.
Docblocks help with lists
When a function expects a list of product arrays, a docblock can describe the nested shape.
<?php
declare(strict_types=1);
/**
* @param list<array{name: string, price: int}> $products
*/
function productTotal(array $products): int
{
$total = 0;
foreach ($products as $product) {
$total += $product['price'];
}
return $total;
}
echo productTotal([
['name' => 'Notebook', 'price' => 499],
['name' => 'Pen', 'price' => 129],
]);
// Prints:
// 628
This kind of docblock is common in codebases that use PHPStan or Psalm.
Document exceptions when they matter
If a function can throw a meaningful exception that callers need to know about, a docblock can make that contract visible.
<?php
declare(strict_types=1);
/**
* @throws InvalidArgumentException when the product name is empty.
*/
function validateProduct(array $product): void
{
if (trim($product['name'] ?? '') === '') {
throw new InvalidArgumentException('Product name is required.');
}
}
Do not add @throws to every function automatically. Use it when the exception is part of how the caller should understand the function.
Keep docblocks true
An outdated docblock is worse than no docblock. It can trick a reader or a static analysis tool into trusting information that is no longer correct.
If a function changes from returning pennies to returning formatted text, update or remove the docblock in the same change.
<?php
declare(strict_types=1);
/**
* @return non-empty-string
*/
function defaultCurrency(): string
{
return 'GBP';
}
Specific docblocks are useful only when they stay accurate.
Comments in real reviews
When reviewing comments and docblocks, ask:
- Does the comment explain a reason that the code itself cannot show?
- Is the docblock more specific than the native PHP type?
- Does the docblock match the current code?
- Would renaming a function or variable remove the need for the comment?
- Is a complex rule documented close to the code that enforces it?
Before moving on, make sure you can remove noisy comments, add useful PHPDoc for array shapes, and recognise when native PHP types are enough.
Practice
Task: Replace Noisy Comments With PHPDoc
Improve the comments and docblocks in this script without changing its output.
<?php
declare(strict_types=1);
// This function totals products.
function productTotal(array $products): int
{
// Set total to zero.
$total = 0;
foreach ($products as $product) {
// Add price.
$total += $product['price'];
}
// Return total.
return $total;
}
$products = [
['name' => 'Notebook', 'price' => 499],
['name' => 'Pen', 'price' => 129],
];
echo productTotal($products);
// Prints:
// 628
Requirements
- Remove comments that only repeat the code.
- Add useful PHPDoc for the product list shape.
- Keep the native
arrayandinttypes. - Keep the output the same.
Show solution
<?php
declare(strict_types=1);
/**
* @param list<array{name: string, price: int}> $products
*/
function productTotal(array $products): int
{
$total = 0;
foreach ($products as $product) {
$total += $product['price'];
}
return $total;
}
$products = [
['name' => 'Notebook', 'price' => 499],
['name' => 'Pen', 'price' => 129],
];
echo productTotal($products);
// Prints:
// 628
The noisy comments are gone. The docblock now adds information that the native array type cannot express: this function expects a list of arrays with name and price keys.