code quality and tooling
Reading and Reviewing PHP Diffs
A diff shows what changed between two versions of files. Reading diffs well is a core job skill because most professional PHP work is reviewed through pull requests.
The goal is not just to see that lines changed. The goal is to understand whether the behaviour changed safely, whether the change matches the task, and whether the proof is good enough.
Diff symbols
In a unified diff:
- lines starting with
-were removed - lines starting with
+were added - unchanged lines provide context
Example:
-if ($subtotal > 5000) {
+if ($subtotal >= 5000) {
return 500;
}
This is a behaviour change. It changes the boundary from "more than GBP 50" to "GBP 50 or more".
Read the intention first
Before reviewing the details, understand the intended change. For example:
Fix discount so orders of GBP 50 or more receive GBP 5 off.
Then read the diff against that intention. The comparison operator change above matches the stated fix.
Look for boundary changes
Many PHP bugs hide in comparisons, empty checks, null checks, and array defaults.
-if ($quantity < 0) {
+if ($quantity <= 0) {
throw new InvalidArgumentException('Quantity must be positive.');
}
This changes whether 0 is allowed. That may be correct, but it needs a test or explanation.
Watch for accidental defaults
Defaults can be useful, but they can also hide bad data.
-$price = $product['price'];
+$price = $product['price'] ?? 0;
This prevents a missing-key warning, but it may silently turn invalid product data into a free product. If price is required, validation is better.
Separate formatting from behaviour
This diff is mostly formatting:
-function total($items){$total=0;foreach($items as $item){$total+=$item['price'];}return $total;}
+function total(array $items): int
+{
+ $total = 0;
+
+ foreach ($items as $item) {
+ $total += $item['price'];
+ }
+
+ return $total;
+}
It also adds types, so it is not purely formatting. A reviewer should check whether the added types match all call sites.
Check tests and verification
A behaviour change should usually include proof.
For the discount boundary fix, good verification might include:
<?php
declare(strict_types=1);
var_dump(discountForSubtotal(4999));
var_dump(discountForSubtotal(5000));
var_dump(discountForSubtotal(5001));
// Prints:
// int(0)
// int(500)
// int(500)
In a real project, that proof might be a unit test instead of a manual script.
Review the whole file list
Before reading line-by-line, look at which files changed.
Ask:
- Are the changed files expected for this task?
- Are generated files included accidentally?
- Did formatting touch unrelated files?
- Did dependency files change?
- Did configuration change?
- Are tests or docs updated where needed?
An unexpected file is not always wrong, but it should be understood.
Red flags in PHP diffs
Look carefully when you see:
?? 0or?? ''added to required data@error suppression- broad
catch (Throwable $e)without handling htmlspecialchars()removed near HTML output- SQL or shell strings built by concatenation
exitadded inside reusable functions- production config changed
.envor secrets added- large formatter diffs mixed with a small bug fix
These patterns are not automatically wrong, but they deserve attention.
What a useful review comment looks like
Good review comments are specific and tied to risk.
This defaults a missing price to 0. Is price optional here? If it is required, can we validate and reject the product instead so we do not create a free line item?
That comment explains the concern and suggests a safer direction.
What to remember
Read diffs by asking what changed, why it changed, what behaviour is affected, what edge cases exist, and how the change was checked. In PHP, pay special attention to input validation, missing array keys, escaping, type changes, and error handling.
Before moving on, make sure you can identify whether a diff is formatting-only, behaviour-changing, or a mix of both.
Practice
Task: Review A Risky Default
Review this diff.
function productPrice(array $product): int
{
- return $product['price'];
+ return $product['price'] ?? 0;
}
The task says: "Stop warnings when a product price is missing."
Requirements
- Identify what behaviour changed.
- Explain why the change may be risky.
- Suggest a safer alternative if
priceis required. - Write the review comment you would leave.
Show solution
The diff changes missing price from a warning into a value of 0.
That may be risky because a missing required price now becomes a free product instead of being rejected.
If price is required, a safer implementation is validation:
<?php
declare(strict_types=1);
function productPrice(array $product): int
{
if (! array_key_exists('price', $product)) {
throw new InvalidArgumentException('Product price is required.');
}
return $product['price'];
}
A useful review comment:
This removes the warning by defaulting a missing price to 0. Is price optional here? If it is required, can we validate and reject the product instead so we do not accidentally create a free line item?