php-standard-library/math
Strictly typed math utilities for PHP with predictable, consistent error handling. Part of the PHP Standard Library project, providing reliable mathematical functions and a stable developer experience for safer numeric operations.
Installation
composer require php-standard-library/math
Ensure your composer.json includes:
"autoload": {
"psr-4": {
"App\\": "app/",
"Math\\": "vendor/php-standard-library/math/src/"
}
}
Run composer dump-autoload.
First Use Case Replace loose arithmetic in a Laravel controller or service:
use Math\Add;
use Math\Division;
// Example: Calculate tax
$tax = Division::safeDivide(Add::calculate($subtotal, $shipping), 100);
Where to Look First
Math\Add, Math\Subtract, Math\Multiply, Math\DivisionMath\SquareRoot, Math\Logarithm, Math\FactorialMath\Range, Math\TypeGuardMath\Exceptions\* (e.g., DivisionByZeroException)src/ for method signatures and @throws annotations.Service Layer Integration
namespace App\Services;
use Math\Add;
use Math\Division;
class PricingService {
public function calculateTotal(float $basePrice, float $taxRate, int $quantity): float
{
$subtotal = Division::safeDivide(
Add::calculate($basePrice, $taxRate),
100
);
return Add::calculate($subtotal, $quantity);
}
}
Model Observers/Accessors
// app/Models/Product.php
public function getDiscountedPriceAttribute(): float
{
return Math\Subtract::calculate(
$this->price,
Math\Division::safeDivide($this->discount_percentage, 100)
);
}
Request Validation
// app/Http/Requests/StoreOrderRequest.php
use Math\Range;
use Illuminate\Validation\Rule;
public function rules(): array
{
return [
'quantity' => [
'required',
Rule::function('valid_quantity')->then(function ($attribute, $value) {
Range::validate($value, 1, 1000);
return true;
}),
],
];
}
Middleware for Input Sanitization
// app/Http/Middleware/SanitizeNumericInput.php
use Math\TypeGuard;
use Closure;
public function handle($request, Closure $next)
{
foreach ($request->all() as $key => $value) {
if (TypeGuard::isNumeric($value)) {
$request->merge([$key => (float) $value]);
}
}
return $next($request);
}
Artisan Commands
// app/Console/Commands/CalculateStats.php
use Math\Mean;
use Math\StandardDeviation;
protected function handle()
{
$data = [1, 2, 3, 4, 5];
$mean = Mean::calculate($data);
$stdDev = StandardDeviation::calculate($data, $mean);
$this->info("Mean: {$mean}, Std Dev: {$stdDev}");
}
Database Query Extensions
// Custom query builder extension
use Illuminate\Database\Query\Builder;
use Math\SquareRoot;
Builder::macro('sqrt', function ($column) {
return $this->selectRaw("sqrt({$column}) as sqrt_{$column}");
});
// Usage:
$results = DB::table('products')
->select('id', 'area')
->sqrt('area')
->get();
// tests/Unit/MathOperationsTest.php
use Math\Division;
use Math\Exceptions\DivisionByZeroException;
use PHPUnit\Framework\TestCase;
class MathOperationsTest extends TestCase {
public function testSafeDivision()
{
$this->assertEquals(2, Division::safeDivide(10, 5));
$this->assertNull(Division::safeDivide(10, 0));
}
public function testDivisionThrowsException()
{
$this->expectException(DivisionByZeroException::class);
Division::divide(10, 0);
}
}
Strict Typing Overhead
Math\SquareRoot::calculate() expect float but may throw InvalidArgumentException for non-numeric inputs.Math\TypeGuard::isNumeric() or Math\Range::validate() pre-calculation.Floating-Point Precision
Math\Division::safeDivide(1, 3) returns 0.33333333333333 (not exact).bcmath or gmp for financial precision:
$result = gmp_div_q($a, $b); // Exact integer division
Exception Handling
Math\Factorial::calculate(1000) may throw Math\OverflowException.Math\Factorial::setMaxInput(100); // Global config
Laravel Caching Quirks
Math\* functions may not serialize properly (e.g., null from safeDivide).serialize():
Cache::put('key', serialize(Math\Add::calculate($a, $b)), $seconds);
Autoloading Conflicts
Math namespace clashes with Laravel’s Math facade.\Math\Add::calculate($a, $b); // Explicit namespace
Performance in Loops
// Before (slow)
foreach ($data as $item) {
$result = Math\Add::calculate($item['a'], $item['b']);
}
// After (faster for trusted data)
foreach ($data as $item) {
$result = $item['a'] + $item['b']; // Native PHP
}
Enable Strict Typing
Add to php.ini or .php.ini:
strict_types=1
Or in composer.json:
"config": {
"platform": {
"php": "8.1",
"ext-bcmath": "1.0"
}
}
Log Exceptions
try {
$result = Math\Logarithm::calculate(-1);
} catch (Math\Exceptions\InvalidInputException $e) {
\Log::error("Math error: {$e->getMessage()}", ['input' => [-1]]);
throw new \RuntimeException('Invalid logarithm input');
}
Static Analysis Use PHPStan to catch type issues early:
vendor/bin/phpstan analyse --level=7 src/
Common Edge Cases
| Function | Edge Case | Fix |
|---|---|---|
Math\SquareRoot |
Negative input | Use Math\Range::validate() |
Math\Division |
Division by zero | Use safeDivide() |
Math\Factorial |
Large inputs (>20) | Set setMaxInput() |
Math\Logarithm |
Non-positive input | Validate with Range |
Global Settings
// Configure max factorial input (default: 20)
Math\Factorial::setMaxInput(100);
// Enable/disable exceptions (default: true)
Math\Config::setThrowExceptions(false);
Laravel Service Provider
// app/Providers/AppServiceProvider.php
use Math\Config;
public function boot()
{
Config::setThrowExceptions(env('MATH_THROW_EXCEPTIONS', true));
}
Environment-Specific Behavior
# .env
MATH_THROW_EXCEPTIONS=false
MATH_FACTORIAL_MAX_INPUT=5
How can I help you explore Laravel packages today?