Accessor formatting causes 'A non-numeric value encountered' error on numeric operations #55308
Replies: 7 comments
-
https://www.php.net/manual/en/migration71.other-changes.php That is just a warning that would become exception is E_ALL if used as error reporting. To avoid issues like this bcmath can be used in this line We had to hack this in our cruFd lib because when dealing with decimals, php + is not as accurate as bcmath so we refreshed the value from db (which can handle decimals like bcmath). The other error is starting here and throws here So, the lib is misused. /**
* The scale (number of digits after the decimal point) of this decimal number.
*
* This must be zero or more.
*/
private readonly int $scale; Here you can see how the lack of typed params bytes larave's ASS on this one /**
* Return a decimal as string.
*
* @param float|string $value
* @param int $decimals
* @return string
*/
protected function asDecimal($value, $decimals)
{
try {
return (string) BigDecimal::of($value)->toScale($decimals, RoundingMode::HALF_UP);
} catch (BrickMathException $e) {
throw new MathException('Unable to cast value to a decimal.', previous: $e);
}
} |
Beta Was this translation helpful? Give feedback.
-
When using Scenario 1: Using
|
Beta Was this translation helpful? Give feedback.
-
@swiftalker you are using the cast wrong acc to documentation
But still the fact that the framework does not cast the explode[1] to int can be considered a bug. Solution case 'decimal':
return $this->asDecimal($value, explode(':', $this->getCasts()[$key], 2)[1]); replaced with case 'decimal':
return $this->asDecimal($value, (int)(explode(':', $this->getCasts()[$key], 2)[1])); |
Beta Was this translation helpful? Give feedback.
-
Thank you for the correction! I think it is just like I just following the documentation, where is the mistake in the typing? |
Beta Was this translation helpful? Give feedback.
-
'decimal:2' in v8 |
Beta Was this translation helpful? Give feedback.
-
It seems like there's an issue with the documentation. In Laravel 8, we used decimal: for casting, which made sense because it aligned with how we define it in migrations (e.g., DECIMAL(15,2)). But in Laravel 12, it’s now decimal:, which can be a bit confusing. The thing is, the precision in casting actually refers to the scale (the number of digits after the decimal point), not the total number of digits. This could lead to some confusion, as we were used to thinking of precision as the total number of digits, just like in migrations. It’d be great if the documentation could clarify (and example too!) this to avoid any confusion. 😅 |
Beta Was this translation helpful? Give feedback.
-
A cast to int must be done there also, coupled with the documentation. If the cast would had been there you would had noticed you get 15 digits after decimal point. |
Beta Was this translation helpful? Give feedback.
-
Laravel Version
12.6.0
PHP Version
8.3.19
Database Driver & Version
SQL Server 2017
Description
When using an accessor method to format a numeric attribute (e.g., cash) in the model, the numeric value becomes a string. This causes issues when performing numeric operations like increment() or decrement() on that attribute.
This issue occurs because formatting the numeric value inside the accessor transforms it into a string, preventing any arithmetic operations from being executed correctly. Specifically, the increment() method fails when the attribute is formatted as a string, resulting in a A non-numeric value encountered error.
Steps To Reproduce
Create a model (e.g.,
User
) with a numeric attribute, for example,cash
.Define an accessor to format the
cash
attribute:Add the necessary casting and fillable properties to the model:
Migration:
Model:
Attempt to increment the
cash
attribute usingincrement()
:The error
A non-numeric value encountered
will be thrown because the value ofcash
is now a string after formatting in the accessor.Beta Was this translation helpful? Give feedback.
All reactions