Skip to content

Modernize Bill with native PHP 8.3 type declarations#117

Open
kai3769 wants to merge 1 commit intohiqdev:masterfrom
kai3769:modernize-bill-types
Open

Modernize Bill with native PHP 8.3 type declarations#117
kai3769 wants to merge 1 commit intohiqdev:masterfrom
kai3769:modernize-bill-types

Conversation

@kai3769
Copy link
Copy Markdown

@kai3769 kai3769 commented Apr 10, 2026

Summary

  • Replace all PHPDoc @var annotations on Bill properties with native PHP typed properties
  • Add return types to methods that were missing them (getId(), calculatePrice(), getComment(), setId(), setComment())
  • Add array return type to BillInterface::getCharges()
  • Use union type int|string|null for $id constructor parameter
  • Fix PHPDoc typo: @param $prices@param $charges in setCharges()
  • Fix @throws \Exception@throws CannotReassignException (actual exception thrown)
  • Use static instead of self/BillInterface for fluent setter return types

Motivation

The project requires PHP 8.3+ (composer.json). Native type declarations improve:

  • Static analysis (Psalm, PHPStan) accuracy
  • IDE autocompletion and refactoring
  • Runtime type safety — catch type errors at assignment, not at usage

Test plan

  • Verify existing PHPUnit tests pass
  • Verify Behat tests pass
  • Run Psalm static analysis

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Refactor
    • Enhanced internal code reliability through improved type safety declarations in the billing module, ensuring more robust data handling and validation.

- Replace PHPDoc @var annotations with native property types
- Add return types to all methods (getId, calculatePrice, getComment, setId, setComment)
- Add union type int|string|null for $id property
- Use nullable types where appropriate (?TargetInterface, ?PlanInterface, ?BillState)
- Change self to static for fluent setters (setQuantity, setCharges)
- Add array return type to BillInterface::getCharges()
- Fix PHPDoc @param typo: $prices → $charges in setCharges
- Fix @throws annotation: \Exception → CannotReassignException

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 10, 2026

📝 Walkthrough

Walkthrough

Added strict type declarations to the Bill class properties and method signatures, replacing PHPDoc-only annotations with typed properties and return types. Updated the BillInterface to explicitly declare the getCharges() return type as array.

Changes

Cohort / File(s) Summary
Bill Class Property Typing
src/bill/Bill.php
Added strict typed declarations for 12 properties ($type, $time, $sum, $quantity, $customer, $target, $requisite, $plan, $charges, $state, $comment, $usageInterval), including nullable types where applicable and default initializations for $requisite (null) and $comment (empty string).
Bill Class Method Signatures
src/bill/Bill.php
Tightened method signatures with explicit return types: calculatePrice(): Money, getId(): int|string|null, setId(int|string): void, setQuantity(): static, setCharges(): static, and getComment()/setComment() with string type hints.
Constructor Parameter Typing
src/bill/Bill.php
Updated constructor parameter $id from untyped to int|string|null.
Bill Interface Return Type
src/bill/BillInterface.php
Updated getCharges() method to explicitly declare array return type, aligning interface contract with implementation.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰✨ Types now dance where docs once dwelled,
Strict casting spells with @vars expelled!
Properties gleam in their native dress,
Return types clear, we code with finesse.
Bill's interface sings in harmony fine! 🎶

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding native PHP 8.3 type declarations to the Bill class and related interface, which is the primary focus of both modified files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/bill/Bill.php`:
- Around line 110-115: In calculatePrice() in Bill.php replace the
float-formatting usage when dividing money by quantity: instead of passing
sprintf('%.14F', $quantity) to $this->sum->divide(), cast the quantity to a
string (e.g. (string)$quantity) so Money::divide() receives the original numeric
string and avoids float precision artifacts; update the call in calculatePrice()
(and apply the same change to other price/charge calculation methods that use
sprintf('%.14F', $quantity) / getQuantity()).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0e04d2d0-079e-428e-91a8-a6721556b3dc

📥 Commits

Reviewing files that changed from the base of the PR and between 196e10e and a38d0b3.

📒 Files selected for processing (2)
  • src/bill/Bill.php
  • src/bill/BillInterface.php

Comment on lines +110 to 115
public function calculatePrice(): Money
{
$quantity = $this->quantity->getQuantity();

return $quantity ? $this->sum->divide(sprintf('%.14F', $quantity)) : $this->sum;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify quantity scalar type and money-division call patterns.
fd -i 'QuantityInterface.php'
rg -n -C3 'interface QuantityInterface|function getQuantity\(' --type=php
rg -n -C3 'calculatePrice\(|->divide\(|sprintf\(\'%.14F\'' --type=php

Repository: hiqdev/php-billing

Length of output: 1929


🏁 Script executed:

fd -i 'quantityinterface.php' --type f

Repository: hiqdev/php-billing

Length of output: 102


🏁 Script executed:

rg -n 'class QuantityInterface|interface QuantityInterface' --type=php -A 10

Repository: hiqdev/php-billing

Length of output: 44


🏁 Script executed:

rg -n 'function getQuantity\(\)' --type=php -B 2 -A 3

Repository: hiqdev/php-billing

Length of output: 1315


🏁 Script executed:

rg -n 'public function divide' --type=php -B 2 -A 5

Repository: hiqdev/php-billing

Length of output: 44


🏁 Script executed:

fd -i 'quantity' --type f

Repository: hiqdev/php-billing

Length of output: 448


🏁 Script executed:

fd -i 'money' --type f | head -20

Repository: hiqdev/php-billing

Length of output: 193


🏁 Script executed:

rg -n 'class Money|interface QuantityInterface' --type=php -A 5

Repository: hiqdev/php-billing

Length of output: 44


🏁 Script executed:

cat composer.json | grep -A 10 '"require"'

Repository: hiqdev/php-billing

Length of output: 367


🏁 Script executed:

head -50 src/bill/Bill.php

Repository: hiqdev/php-billing

Length of output: 1248


🏁 Script executed:

find . -name "QuantityInterface.php" -o -name "*Quantity*.php" | xargs ls -la

Repository: hiqdev/php-billing

Length of output: 1252


🏁 Script executed:

cat vendor/hiqdev/php-units/src/QuantityInterface.php

Repository: hiqdev/php-billing

Length of output: 3043


🏁 Script executed:

rg -n 'getQuantity' vendor/hiqdev/php-units/src/ --type=php -B 2 -A 2

Repository: hiqdev/php-billing

Length of output: 2688


🏁 Script executed:

rg -n '->divide\(' src/ --type=php -B 2 -A 2

Repository: hiqdev/php-billing

Length of output: 466


🏁 Script executed:

web_search
MoneyPHP Money::divide() method signature and type requirements

Repository: hiqdev/php-billing

Length of output: 261


🏁 Script executed:

rg -n 'divide\(' src/ --type=php -B 2 -A 2

Repository: hiqdev/php-billing

Length of output: 1523


🌐 Web query:

MoneyPHP Money divide method signature PHP

💡 Result:

Web search failed: Server error: no LLM provider could handle the message


Use string casting instead of float formatting in monetary division.

The sprintf('%.14F', $quantity) pattern formats the quantity as a float string before passing it to Money::divide(). This float formatting stage can introduce precision artifacts. Since getQuantity() already returns int|float|string, a simple string cast is safer and more direct.

Proposed fix
 public function calculatePrice(): Money
 {
     $quantity = $this->quantity->getQuantity();

-    return $quantity ? $this->sum->divide(sprintf('%.14F', $quantity)) : $this->sum;
+    if ($quantity === 0 || $quantity === '0') {
+        return $this->sum;
+    }
+
+    return $this->sum->divide((string)$quantity);
 }

Note: This same pattern appears in multiple price and charge calculation classes—consider applying the same fix systematically.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public function calculatePrice(): Money
{
$quantity = $this->quantity->getQuantity();
return $quantity ? $this->sum->divide(sprintf('%.14F', $quantity)) : $this->sum;
}
public function calculatePrice(): Money
{
$quantity = $this->quantity->getQuantity();
if ($quantity === 0 || $quantity === '0') {
return $this->sum;
}
return $this->sum->divide((string)$quantity);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/bill/Bill.php` around lines 110 - 115, In calculatePrice() in Bill.php
replace the float-formatting usage when dividing money by quantity: instead of
passing sprintf('%.14F', $quantity) to $this->sum->divide(), cast the quantity
to a string (e.g. (string)$quantity) so Money::divide() receives the original
numeric string and avoids float precision artifacts; update the call in
calculatePrice() (and apply the same change to other price/charge calculation
methods that use sprintf('%.14F', $quantity) / getQuantity()).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant