langleyfoxall/math_eval
Safely evaluate math expressions in PHP. langleyfoxall/math_eval parses and computes strings with operators, brackets, and common functions, ideal for user-defined formulas and configuration values without using eval(). Lightweight and easy to integrate in Laravel or any PHP app.
Installation:
composer require langleyfoxall/math_eval
Ensure your project uses PHP 8.0+ (HHVM is no longer supported).
First Use Case: Evaluate a basic arithmetic expression in a Laravel controller or service:
use MathEval\Evaluator;
$result = (new Evaluator())->evaluate('2 + 3 * (4 - 1)');
// Returns 11 (respects operator precedence)
Where to Look First:
sin(), log()).Evaluator.php to understand parsing logic and safety mechanisms.tests/ for edge cases (e.g., variable substitution, error handling).$evaluator = new Evaluator();
$result = $evaluator->evaluate('10 / 2 + 3'); // Returns 8
Pass an associative array for dynamic values:
$result = $evaluator->evaluate('a * b + c', [
'a' => 5,
'b' => 3,
'c' => 2
]);
// Returns 17 (5*3 + 2)
Service Provider:
// app/Providers/AppServiceProvider.php
public function register()
{
$this->app->singleton('math', function () {
return new Evaluator();
});
}
Facade (Optional):
// app/Facades/Math.php
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class Math extends Facade
{
protected static function getFacadeAccessor() { return 'math'; }
}
Usage in Controllers:
$result = Math::evaluate('2 ** 3'); // Returns 8 (exponentiation)
Sanitize user input before evaluation (e.g., in Laravel Form Requests):
public function rules()
{
return [
'expression' => 'required|string|regex:/^[0-9+\-*\/%^().\s]+$/i',
];
}
Cache results for performance-critical paths:
$cacheKey = 'math:' . md5($expression);
$result = Cache::remember($cacheKey, now()->addHours(1), function () use ($evaluator, $expression) {
return $evaluator->evaluate($expression);
});
Wrap evaluations in try-catch blocks:
try {
$result = $evaluator->evaluate($userInput);
} catch (\MathEval\Exception\ParseError $e) {
Log::error("Invalid expression: {$userInput}", ['error' => $e->getMessage()]);
return response()->json(['error' => 'Invalid math expression'], 400);
}
discount_formula column).$formula = Product::find($id)->discount_formula;
$discount = Math::evaluate($formula, [
'price' => $cartTotal,
'customer_tier' => $user->tier,
]);
'alert_rules' => [
'high_traffic' => '(visitors / avg_visitors) > 2',
],
$metrics = collect([...]);
$rule = config('alert_rules.high_traffic');
if (Math::evaluate($rule, $metrics->toArray())) {
Alert::trigger('high_traffic');
}
$results = User::query()
->get()
->map(function ($user) {
$user->score = Math::evaluate('(activity + reputation) / 2', [
'activity' => $user->activity_score,
'reputation' => $user->reputation,
]);
return $user;
});
Add Custom Functions:
The package uses mossadal/math-parser. Extend by subclassing Evaluator:
class CustomEvaluator extends Evaluator
{
protected function getFunctions()
{
return array_merge(parent::getFunctions(), [
'custom_func' => function ($a, $b) {
return $a + $b * 2;
},
]);
}
}
Laravel Service Container Binding:
$this->app->bind('math', function () {
return new CustomEvaluator();
});
Unit Tests:
public function testBasicArithmetic()
{
$evaluator = new Evaluator();
$this->assertEquals(15, $evaluator->evaluate('3 * 5'));
}
Security Tests:
public function testMaliciousInput()
{
$this->expectException(\MathEval\Exception\ParseError::class);
$evaluator->evaluate('system("rm -rf")');
}
Precompile Expressions: For repeated use, parse expressions once and reuse:
$parser = new \MathParser\Parser();
$ast = $parser->parse('2 + 3 * x');
$result = $evaluator->evaluateAST($ast, ['x' => 5]); // Returns 17
Benchmark Alternatives:
Compare with league/math or symfony/math for complex workloads.
No User-Defined Functions:
sin(), log()).Evaluator and override getFunctions() (see Extending Functionality above).Floating-Point Precision:
0.1 + 0.2 !== 0.3).bcmath:
$result = bcadd($evaluator->evaluate('0.1 + 0.2'), 0, 10);
Recursive Expressions:
x = x + 1 may cause infinite loops.Large Numbers:
2^1000).gmp or bcmath:
$result = gmp_strval(gmp_pow('2', 1000));
HHVM Legacy Code:
No Error Context:
try-catch to capture errors.Enable Debug Mode:
$evaluator = new Evaluator();
$evaluator->setDebug(true); // Logs parsing steps (if supported)
Inspect AST (Abstract Syntax Tree):
$parser = new \MathParser\Parser();
$ast = $parser->parse('2 + 3 * x');
dd($ast); // Debug the parsed structure
Common Errors:
ParseError: Invalid syntax (e.g., unbalanced parentheses).UndefinedVariable: Missing variable in substitution array.How can I help you explore Laravel packages today?