I am having difficulty passing array as an argument. I am getting an error string to array conversion. the $optional variable sometimes need to get a string as a parameter and sometimes an array. Please check my code below. Many Thanks
function getLists($str, array $items,$optional=null, ){
$items1 = array_map(function($x) use ($optional) { return "$x $optional"; }, $items);
$itemsCount = count($items1);
$sentence = '';
if ($itemsCount == 1) {
$sentence = $items[0] . '.';
} else {
if($optional == null)
{
$partial = array_slice($items, 0, $itemsCount-1);
$sentence = implode(', ', $partial) . ' and ' . $items[$itemsCount-1];
}
if(is_string($optional))
{
$partial = array_slice($items1, 0, $itemsCount-1);
$sentence = implode(', ', $partial). ' and ' . $items1[$itemsCount-1];
}
else
{
$partial = array_slice($items1, 0, $itemsCount-1);
$sentence = implode(', ', $partial). ' and ' . $items1[$itemsCount-1];
}
}
return $str.': '.$sentence.'.';
}
Here are what I am trying to do, the following two are working correctly
getList("What do you want",array("chocolate","icecream","shake"));
getList("Ice Cream has",array("chocolate","vanilla","mango"),"flavour");
But when I replace try to pass [] as parameter then I got an error array to string conversion warning
getList("The color required",array("green","red","blue"),['chilli','onion','berry']);
So when I pass this parameter and my output should be like:
I am not getting the correct output that should be like:
The color required: green chilli,red onion and blue berry.
Instead I am getting:
The color required: green Array, red Array and blue Array.
In the first line of the body of your function you have a following statement:
return "$x $optional";
As you said, the $optional variable can be a string or an array.
If it's a string there is no problem here. Your string will be inserted there. But if it's an array, then it's a syntax error. You're trying to put the whole array there. Instead you should put just one element of that array.
What you should do, is to replace the first line ($items1 = ...) of your function's body to:
$items1 = [];
if( is_array($optional) ) {
for($i=0 ; $i < count($items) ; $i++) {
$items1[] = "$items[$i] $optional[$i]";
}
} else {
$items1 = array_map(function($x) use ($optional) { return "$x $optional"; }, $items);
}
I suggest you to use the gettype function to test the type of $optional before applying any logic https://www.php.net/manual/fr/function.gettype.php
Is there a way to convert any value especially boolean and arrays into strings? I want to do this for a cleaner error message in a function. Right now all I can get in this example below it this for an error message
Fatal error: Uncaught InvalidArgumentException: $argument cannot be in /file.php:## Stack trace: #0 /file.php:(##): myFunction(false) #1 {main} thrown in /file.php on line 47
I want it to say "$argument cannot be false" not "$argument cannot be "
<?php
myFunction(false);
myFunction(array('a', 'b'));
//Version 0.5
function myFunction($argument) {
if (!is_string($argument)) {
throw new InvalidArgumentException('$argument cannot be ' . strval($argument));
}
//...
}
?>
Best way to convert most value types to string is using json_encode.
An array for example would become ["a","b"].
Just json_encode($argument)
I would use gettype and/or var_export:
throw new InvalidArgumentException('$argeument cannot be ' . gettype($argeument) . ' ' . var_export($argeument, true));
Or buffer output of var_dump and you can see it all:
ob_start();
var_dump($argeument);
$text = ob_get_clean();
throw new InvalidArgumentException('$argeument cannot be ' . $text);
Perhaps (in lieu of function (string $value), which I recommend)?
class InvalidArgumentType extends InvalidArgumentException
{
public function __construct(int $position, string $requiredType, $value)
{
$encoded = json_encode($value);
if (strlen($encoded) > 10) {
$encoded = sprintf('%s ... %s', substr($encoded, 0, 10), substr($encoded, -1));
}
$inferredType = is_object($value) ? get_class($value) : gettype($value);
parent::__construct(sprintf(
'Argument %d value %s should be %s but is %s.',
$position,
$encoded,
$requiredType,
$inferredType
));
}
}
class Foo {}
echo (new InvalidArgumentType(1, 'string', new Foo()))->getMessage().PHP_EOL;
echo (new InvalidArgumentType(2, 'string', [1,2,3,4,5,6,7,8,9,10]))->getMessage().PHP_EOL;
echo (new InvalidArgumentType(3, 'string', 123))->getMessage().PHP_EOL;
echo (new InvalidArgumentType(2, 'string', null))->getMessage();
Gives:
Argument 1 value {} should be string but is Foo.
Argument 2 value [1,2,3,4,5 ... ] should be string but is array.
Argument 3 value 123 should be string but is integer.
Argument 2 value null should be string but is NULL.
https://3v4l.org/ko7o1
I'm trying to find a fast way to remove zero decimals from number values like this:
echo cleanNumber('125.00');
// 125
echo cleanNumber('966.70');
// 966.7
echo cleanNumber(844.011);
// 844.011
Does exists some optimized way to do that?
$num + 0 does the trick.
echo 125.00 + 0; // 125
echo '125.00' + 0; // 125
echo 966.70 + 0; // 966.7
Internally, this is equivalent to casting to float with (float)$num or floatval($num) but I find it simpler.
you could just use the floatval function
echo floatval('125.00');
// 125
echo floatval('966.70');
// 966.7
echo floatval('844.011');
// 844.011
This is what I use:
function TrimTrailingZeroes($nbr) {
return strpos($nbr,'.')!==false ? rtrim(rtrim($nbr,'0'),'.') : $nbr;
}
N.B. This assumes . is the decimal separator. It has the advantage that it will work on arbitrarily large (or small) numbers since there is no float cast. It also won't turn numbers into scientific notation (e.g. 1.0E-17).
If you want to remove the zero digits just before to display on the page or template.
You can use the sprintf() function
sprintf('%g','125.00');
// 125
sprintf('%g','966.70');
// 966.7
sprintf('%g',844.011);
// 844.011
Simply adding + to your string variable will cause typecast to (float) and removes zeros:
var_dump(+'125.00'); // double(125)
var_dump(+'966.70'); // double(966.7)
var_dump(+'844.011'); // double(844.011)
var_dump(+'844.011asdf');// double(844.011)
For everyone coming to this site having the same problem with commata instead, change:
$num = number_format($value, 1, ',', '');
to:
$num = str_replace(',0', '', number_format($value, 1, ',', '')); // e.g. 100,0 becomes 100
If there are two zeros to be removed, then change to:
$num = str_replace(',00', '', number_format($value, 2, ',', '')); // e.g. 100,00 becomes 100
More here: PHP number: decimal point visible only if needed
You should cast your numbers as floats, which will do this for you.
$string = "42.422005000000000000000000000000";
echo (float)$string;
Output of this will be what you are looking for.
42.422005
$x = '100.10';
$x = preg_replace("/\.?0*$/",'',$x);
echo $x;
There is nothing that can't be fixed with a simple regex ;)
http://xkcd.com/208/
Typecast to a float.
$int = 4.324000;
$int = (float) $int;
Be careful with adding +0.
echo number_format(1500.00, 2,".",",")+0;
//1
Result of this is 1.
echo floatval('1,000.00');
// 1
echo floatval('1000.00');
//1000
Sometimes, especially in case of monetary amounts, you want to remove the zeros only if they are 2, you don't want to print € 2.1 instead of € 2.10.
An implementation could be:
function formatAmount(string|float|int $value, int $decimals = 2): string
{
if (floatval(intval($value)) === floatval($value)) {
// The number is an integer. Remove all the decimals
return (string)intval($value);
}
return number_format($value, $decimals);
}
Examples of expected outputs:
0.1000 => 0.10
20.000 => 20
1.25 => 1.25
Example 1
$value =81,500.00;
{{rtrim(rtrim(number_format($value,2),0),'.')}}
output
81,500
Example 2
$value=110,763.14;
{{rtrim(rtrim(number_format($value,2),0),'.')}}
output
110,763.14
Due to this question is old. First, I'm sorry about this.
The question is about number xxx.xx but in case that it is x,xxx.xxxxx or difference decimal separator such as xxxx,xxxx this can be harder to find and remove zero digits from decimal value.
/**
* Remove zero digits (include zero trails - 123.450, 123.000) from decimal value.
*
* #param string|int|float $number The number can be any format, any where use in the world such as 123, 1,234.56, 1234.56789, 12.345,67, -98,765.43
* #param string The decimal separator. You have to set this parameter to exactly what it is. For example: in Europe it is mostly use "," instead of ".".
* #return string Return removed zero digits from decimal value. Only return as string!
*/
function removeZeroDigitsFromDecimal($number, $decimal_sep = '.')
{
$explode_num = explode($decimal_sep, $number);
if (is_countable($explode_num) && count($explode_num) > 1) {
// if exploded number is more than 1 (Example: explode with . for nnnn.nnn is 2)
// replace `is_countable()` with `is_array()` if you are using PHP older than 7.3.
$explode_num[count($explode_num)-1] = preg_replace('/(0+)$/', '', $explode_num[count($explode_num)-1]);
if ($explode_num[count($explode_num)-1] === '') {
// if the decimal value is now empty.
// unset it to prevent nnn. without any number.
unset($explode_num[count($explode_num)-1]);
}
$number = implode($decimal_sep, $explode_num);
}
unset($explode_num);
return (string) $number;
}
And here is the code for test.
$tests = [
1234 => 1234,
-1234 => -1234,
'12,345.67890' => '12,345.6789',
'-12,345,678.901234' => '-12,345,678.901234',
'12345.000000' => '12345',
'-12345.000000' => '-12345',
'12,345.000000' => '12,345',
'-12,345.000000000' => '-12,345',
];
foreach ($tests as $number => $assert) {
$result = removeZeroDigitsFromDecimal($number);
assert($result === (string) $assert, new \Exception($result . ' (' . gettype($result) . ') is not matched ' . $assert . ' (' . gettype($assert) . ')'));
echo $number . ' => ' . (string) $assert . '<br>';
}
echo '<hr>' . PHP_EOL;
$tests = [
1234 => 1234,
-1234 => -1234,
'12.345,67890' => '12.345,6789',
'-12.345.678,901234' => '-12.345.678,901234',
'12345,000000' => '12345',
'-12345,000000' => '-12345',
'-12.345,000000000' => '-12.345',
'-12.345,000000,000' => '-12.345,000000',// this is correct assertion. Weird ,000000,000 but only last 000 will be removed.
];
foreach ($tests as $number => $assert) {
$result = removeZeroDigitsFromDecimal($number, ',');
assert($result === (string) $assert, new \Exception($result . ' (' . gettype($result) . ') is not matched ' . $assert . ' (' . gettype($assert) . ')'));
echo $number . ' => ' . (string) $assert . '<br>';
}
All tests should be pass and no errors.
Why '-12.345,000000,000' will be '-12.345,000000' not '-12.345'?
Because this function is for remove zero digits (include zero trails) from decimal value. It is not validation for the correct number format. That should be another function.
Why always return as string?
Because it is better to use in calculation with bcxxx functions, or use with big number.
$str = 15.00;
$str2 = 14.70;
echo rtrim(rtrim(strval($str), "0"), "."); //15
echo rtrim(rtrim(strval($str2), "0"), "."); //14.7
I found this solution is the best:
public function priceFormat(float $price): string
{
//https://stackoverflow.com/a/14531760/5884988
$price = $price + 0;
$split = explode('.', $price);
return number_format($price, isset($split[1]) ? strlen($split[1]) : 2, ',', '.');
}
The following is much simpler
if(floor($num) == $num) {
echo number_format($num);
} else {
echo $num;
}
You can try the following:
rtrim(number_format($coin->current_price,6),'0.')
Complicated way but works:
$num = '125.0100';
$index = $num[strlen($num)-1];
$i = strlen($num)-1;
while($index == '0') {
if ($num[$i] == '0') {
$num[$i] = '';
$i--;
}
$index = $num[$i];
}
//remove dot if no numbers exist after dot
$explode = explode('.', $num);
if (isset($explode[1]) && intval($explode[1]) <= 0) {
$num = intval($explode[0]);
}
echo $num; //125.01
the solutions above are the optimal way but in case you want to have your own you could use this. What this algorithm does it starts at the end of string and checks if its 0, if it is it sets to empty string and then goes to the next character from back untill the last character is > 0
$value = preg_replace('~\.0+$~','',$value);
You can use:
print (floatval)(number_format( $Value), 2 ) );
Thats my small solution...
Can included to a class and set vars
private $dsepparator = '.'; // decimals
private $tsepparator= ','; // thousand
That can be set by constructor and change to users lang.
class foo
{
private $dsepparator;
private $tsepparator;
function __construct(){
$langDatas = ['en' => ['dsepparator' => '.', 'tsepparator' => ','], 'de' => ['dsepparator' => ',', 'tsepparator' => '.']];
$usersLang = 'de'; // set iso code of lang from user
$this->dsepparator = $langDatas[$usersLang]['dsepparator'];
$this->tsepparator = $langDatas[$usersLang]['tsepparator'];
}
public function numberOmat($amount, $decimals = 2, $hideByZero = false)
{
return ( $hideByZero === true AND ($amount-floor($amount)) <= 0 ) ? number_format($amount, 0, $this->dsepparator, $this->tsepparator) : number_format($amount, $decimals, $this->dsepparator, $this->tsepparator);
}
/*
* $bar = new foo();
* $bar->numberOmat('5.1234', 2, true); // returns: 5,12
* $bar->numberOmat('5', 2); // returns: 5,00
* $bar->numberOmat('5.00', 2, true); // returns: 5
*/
}
This is my solution.
I want to keep ability to add thousands separator
$precision = 5;
$number = round($number, $precision);
$decimals = strlen(substr(strrchr($number, '.'), 1));
return number_format($number, $precision, '.', ',');
This is a simple one line function using rtrim, save separator and decimal point :
function myFormat($num,$dec)
{
return rtrim(rtrim(number_format($num,$dec),'0'),'.');
}
Simple and accurate!
function cleanNumber($num){
$explode = explode('.', $num);
$count = strlen(rtrim($explode[1],'0'));
return bcmul("$num",'1', $count);
}
I use this simple code:
define('DECIMAL_SEPARATOR', ','); //To prove that it works with different separators than "."
$input = "50,00";
$number = rtrim($input, '0'); // 50,00 --> 50,
$number = rtrim($number, DECIMAL_SEPARATOR); // 50, --> 50
echo $number;
Seems a bit too easy to be the really correct solution, but it works just fine for me. You should do some tests with the inputs you'll be getting before using this.
Assuming the amount is a string with 2 decimal places, then you can use:
protected function removeZerosDecimals(string $money): string
{
$formatter = new NumberFormatter('en_US', NumberFormatter::CURRENCY);
$uselessDecimals = sprintf(
'%s00',
$formatter->getSymbol(NumberFormatter::DECIMAL_SEPARATOR_SYMBOL)
);
if (!str_ends_with($money, $uselessDecimals)) {
return $money;
}
$len = mb_strlen($money);
return mb_substr($money, 0, $len - mb_strlen($uselessDecimals));
}
That will work as expected for ?any? currency, like $500.00 and R$ 500,00.
function removeZerosAfterDecimals($number) {
$number = trim($number);
if($number <= 0 || empty($number)) {
return $number;
}
$ary = explode('.', $number);
if(count($ary) <= 1) {
return $number;
}
$reverseAry = array_reverse($ary);
$endSearch = false;
$newNumber = [];
for($i=0; $i<count($reverseAry); $i++) {
if($reverseAry[$i] != 0 && $endSearch === false) {
$newNumber[] = $reverseAry[$i];
$endSearch = true;
} else if ($endSearch === true) {
$newNumber[] = $reverseAry[$i];
}
}
return implode('.',array_reverse($newNumber));
}
//output: 10.0.1.0 => 10.0.1
//output: 10.0.1 => 10.0.1
//output: 10.1.2 => 10.1.2
//output: 10.0.0 => 10
This function will only remove the trailing zero decimals
This Code will remove zero after point and will return only two decimal digits.
$number=1200.0000;
str_replace('.00', '',number_format($number, 2, '.', ''));
Output will be: 1200
Ultimate Solution: The only safe way is to use regex:
echo preg_replace("/\.?0+$/", "", 3.0); // 3
echo preg_replace("/\d+\.?\d*(\.?0+)/", "", 3.0); // 3
it will work for any case