Function within str_replace not working correctly - php

Please see my code below, I am trying to put a function containing an if statement within str_replace, however, it is not injecting it into the script, thank you in advance for your help. Basically I need to replace [price] in the string with this if statement.
function price(){
if ($_SESSION['vat'] == "ex"){
echo('£'.$row_products['price'].'Ex. VAT');
} ?>
<?php if ($_SESSION['vat'] == "inc"){
$total_price = $row_products['price'] *= (1 + $VATrate / 100);
echo('£');
printf("%.2f", $total_price);
echo('Inc. VAT');
}
}
$main_description = str_replace('[price]', price(), $row_products['description']);

Not tested but something along the lines of this should do the trick:
function price() {
if ($_SESSION['vat'] == "ex"){
return '£'.$row_products['price'].'Ex. VAT';
}
if ($_SESSION['vat'] == "inc"){
$total_price = $row_products['price'] *= (1 + $VATrate / 100);
return sprintf("%s %.2f %s", "£", $total_price, 'Inc. VAT');
}
}

You can't echo result inside a function you need to return a value. Your function should look something like this:
function price() {
$result = ''
if ($_SESSION['vat'] == "ex"){
$result .= '£'.$row_products['price'].'Ex. VAT' . "\n"
}
if ($_SESSION['vat'] == "inc") {
$total_price = $row_products['price'] *= (1 + $VATrate / 100);
$result .= '£';
$result .= sprintf("%.2f", $total_price);
$result .= 'Inc. VAT';
}
return $result;
}
You concatenate the string an then return it at the end.

The commentary is in the comments:
// When you create functions do not assume that variables
// will just magically be available inside it. If you need
// to use some variable inside a function then define them
// as arguments.
function price($price, $vat) {
// Never use a variable or array index without
// first making sure that it exists! You will
// get error messages if they do not exist.
if ( ! isset($_SESSION['vat'])) {
trigger_error('The session variable "vat" is not set');
}
// Since you use 'ex' and 'inc' to figure out if the
// VAT is included or not, what happens it the value
// is neither of those? Maybe $_SESSION['vat'] should be
// a boolean value instead? (I.e. true or false, as
// opposed to one of N values.)
$vatInfo = 'VAT may or may not be included...';
// VAT excluded
if ($_SESSION['vat'] === 'ex') {
$vatInfo = 'Ex. VAT';
}
// VAT included
elseif ($_SESSION['vat'] === 'inc') {
$vatInfo = 'Inc. VAT';
// The value of the $price variable will not be changed
// after this so we can just overwrite it here.
$price = ($price * (1 + $vat / 100));
}
// When it comes to money it is nice to format it so
// that it looks good to the user. number_format() was
// made for this.
$price = number_format($price, 2);
// And *return* it, as opposed to echo'ing it.
return "£{$price} {$vatInfo}";
}
// Pass in the price and VAT rate as arguments so that
// they can be used inside the function.
$price = price($row_products['price'], $VATrate);
$main_description = str_replace('[price]', $price, $row_products['description']);

Related

Function doesn't save variable

I'm trying to add 1 to a number each time a function is called, but for some reason, the total number is always same.
Here is my current code:
<?php
$total;
function draw_card() {
global $total;
$total=$total+1;
echo $total;
}
draw_card();
draw_card();
?>
Personally, I would not use globals, but if I was forced at gunpoint I would handle state within the function, so outside variables did not pollute the value. I would also make an arbitrary long key name which I would not use anywhere else.
<?php
function draw_card($initial = 0) {
$GLOBALS['draw_card_total'] = (
isset($GLOBALS['draw_card_total']) ? $GLOBALS['draw_card_total']+1 : $initial
);
return $GLOBALS['draw_card_total'];
}
// optionally set your start value
echo draw_card(1); // 1
echo draw_card(); // 2
https://3v4l.org/pinSi
But I would more likely go with a class, which holds state by default, plus its more verbose as to whats happening.
<?php
class cards {
public $total = 0;
public function __construct($initial = 0)
{
$this->total = $initial;
}
public function draw()
{
return ++$this->total;
}
public function getTotal()
{
return $this->total;
}
}
$cards = new cards();
echo $cards->draw(); // 1
echo $cards->draw(); // 2
echo $cards->getTotal(); // 2
https://3v4l.org/lfbcL
Since it is global already, you can use it outside the function.
<?php
$total;
function draw_card() {
global $total;
$total=$total+1;
//echo $total;
}
draw_card();
draw_card();
draw_card();
echo "Current Count :", $total;
?>
Result :
Current Count :3
This will increment the number of times you call the function.
Since you echoed the result/total each time without a delimiter, you might have considered the output to be 12(Assumption)
Functions have a scope.. you just need to bring $total into the scope of the function... best to not do it globally but as an argument.
$total = 0;
function draw_card($total) {
return $total + 1;
}
$total = draw_card($total);
//Expected Output = 1
$total = draw_card($total);
//Expected Output = 2

Why substr() doesn't work correctly with a number that has a leading zero?

I have this script:
function DecryptId($id) {
$first_digit = substr($id, 0,1);
if ( $first_digit == 0 ) {
return 'yes';
} else {
return 'no';
}
}
$id = 014;
echo DecryptId($id);
//=> no
Demo
Why it prints no? I expect it prints yes. Because the value of $id starts with 0. What's wrong?
EDIT: In reality I'm passing $id like this: DecryptId($_POST['au']);. $_POST['au'] is containing a number. Something like these:
23
43552
0153
314
09884
As you see, sometimes that number starts with 0. And I need to pass it as a string. How can I do that?
Because of the leading zero, PHP will be parsing that number as octal. Even if it didn't do this, most languages will strip off the leading zeros (since they don't actually form part of the number). This means that $id will evaluate to 12.
Are you sure you don't want to declare it as a string? ($id = "014")
Your function is working fine the issue is that you are passing a number in your function when you should provide a string. So in the case that your variable type is integer the leading zero will eventually fly away.
You can add something to your function to check the variable type and inform the user.
function DecryptId($id) {
$type = gettype( $id );
if($type!= "string") {
echo "Your variable has type ".$type.". Use a 'string' type variable";
return;
}
$first_digit = substr($id, 0,1);
if ( $first_digit == 0 ) {
return 'yes';
} else {
return 'no';
}
}
$id = 014;
echo DecryptId($id);
echo "\n";
$id = '014';
echo DecryptId($id);
Try the above example in PHP Sandbox
try this
<?php
function DecryptId($id) {
$first_digit = substr($id, 0,1);
if ( $first_digit == 0 ) {
return 'yes';
} else {
return 'no';
}
}
$id = '014';
echo DecryptId($id);
?>

Change '-' to variable and use this variable to call exact value

For example:
$k = "+";
$q = 8;
echo $array[$q+1];
But I want the following:
echo $array[$q$k1];
So it basically says "call the value of array which is 8+1 so 9." and if I want to call 7 I can do $k = "-".
In PHP, you can not treat operators as variables.
Still, there two basic ways you can achieve the same effect.
You can use a conditional and specify the values accordingly:
$r = 1; //the value you're adding; moved to a variable for clarity
$op = '+'; //+ means add; anything else means subtract
echo $array[$q + ($op === '+' ? $r : -$r)];
//or
if($op === '+') {
echo $array[$q + $r];
} else {
echo $array[$q - $r];
}
Or you can change the operation into a multiplication:
echo $array[$q + (($op === '+' ? 1 : -1) * $r)];
Either form will work; it's just a matter of what is most convenient for your code.

PHP using variables outside of a function

I was wondering if someone could help me out.
I'm writing some PHP functions where I would like to use a variable inside a function and then use the updated variable outside of the function.
eg
$subTotal += $priceToShow * $ct_qty;
adminCharge($subTotal);
function adminCharge($loggedInfoprice, $subTotal){
if (($loggedInfoprice == 5)||($loggedInfoprice == 6)){
$packagingCurrency = "$";
$packagingPrice = "63";
$packagingPricing = $packagingCurrency.$packagingPrice;
}else {
$packagingCurrency = "£";
$packagingPrice = "30";
$packagingPricing = $packagingCurrency.$packagingPrice;
}
if(isset($packagingPrice)){
$subTotal = $subTotal + $packagingPrice;
}
}
<?php echo $subTotal; ?>
The echo'd $subTotal only seems to show the value from before the function.
Is it possible to extract both $subTotal and $packagingPricing from the function?
Thanks in advance.
Updated the function
function adminCharge(&$subTotal){
// do things
}
or
$subTotal = adminCharge($subTotal);
function adminCharge($subTotal){
//do things
return $subTotal;
}
In the first case, you pass $subTotal variable as a reference, so all all changes will be reflected to "outside" variable.
In the second case, you pass it and return new value, so is easy to understand why is working.
Please, pay attention
First solution - however - can lead you to side effect that will be difficult to understand and debug
Update
If you want to "extract" (so return) two variables, you can do the following
list($subTotal,$packagingPrice) = adminCharge($subTotal);
function adminCharge($subTotal){
if(isset($packagingPrice)){
$subTotal = $subTotal + $packagingPrice;
}
return array($subTotal, $packagingPrice);
}
function adminCharge($subTotal, $packagingPrice){
if(isset($packagingPrice)){
$subTotal = $subTotal + $packagingPrice;
}
return $subTotal;
}
Use it like this:
$subTotal = adminCharge($subTotal, $packagingPrice);
You don't return anything, so you could use globals but i wouldn't recommend it.. Take a look though, because that's what your asking for: http://www.php.net/global
In my opinion, change your function:
function adminCharge($subTotal){
global $packagingPrice
if(isset($packagingPrice)){
$subTotal = $subTotal + $packagingPrice;
}
return $subTotal;
}
$subTotal += $priceToShow * $ct_qty;
$subTotal = adminCharge($subTotal);
Also keep in mind you didn't had $packagingPrice in your function, so i added it with global. Otherwise it wouldn't work :)
You have to understand the variable scope read here.
In short, there are 3 options.
Use global keyword:
$a = 0;
function foo(){
global $a;
$a += 1;
}
Use pass by reference:
$a = 0;
function foo(&$b){
$b += 1;
}
foo($a);
Collect return value of the function:
$a = 0;
function foo($b){
return $b + 1;
}
$a = foo($a);
you need to use pass the variable by reference or global
option 1
function adminCharge(&$subTotal){
if(isset($packagingPrice)){
$subTotal = $subTotal + $packagingPrice;
}
return array($subTotal, $packagingPrice);
}
option 2
function adminCharge()
{
global $subTotal;
if(isset($packagingPrice))
{
$subTotal = $subTotal + $packagingPrice;
}
return array($subTotal, $packagingPrice);
}

PHP loops to check that a set of numbers are consecutive

I'm trying to loop through a set of records, all of which have a "number" property. I am trying to check if there are 3 consecutive records, e.g 6, 7 and 8.
I think i'm almost there with the code below, have hit the wall though at the last stage - any help would be great!
$nums = array();
while (count($nums <= 3))
{
//run through entries (already in descending order by 'number'
foreach ($entries as $e)
{
//ignore if the number is already in the array, as duplicate numbers may exist
if (in_array($e->number, $num))
continue;
else
{
//store this number in the array
$num[] = $e->number;
}
//here i need to somehow check that the numbers stored are consecutive
}
}
function isConsecutive($array) {
return ((int)max($array)-(int)min($array) == (count($array)-1));
}
You can achieve the same result without looping, too.
If they just have to be consecutive, store a $last, and check to make sure $current == $last + 1.
If you're looking for n numbers that are consecutive, use the same, except also keep a counter of how many ones fulfilled that requirement.
$arr = Array(1,2,3,4,5,6,7,343,6543,234,23432,100,101,102,103,200,201,202,203,204);
for($i=0;$i<sizeof($arr);$i++)
{
if(isset($arr[$i+1]))
if($arr[$i]+1==$arr[$i+1])
{
if(isset($arr[$i+2]))
if($arr[$i]+2==$arr[$i+2])
{
if(isset($arr[$i+3]))
if($arr[$i]+3==$arr[$i+3])
{
echo 'I found it:',$arr[$i],'|',$arr[$i+1],'|',$arr[$i+2],'|',$arr[$i+3],'<br>';
}//if3
}//if 2
}//if 1
}
I haven't investigated it thoroughly, maybe can be improved to work faster!
This will confirm if all items of an array are consecutive either up or down.
You could update to return an array of [$up, $down] or another value instead if you need direction.
function areAllConsecutive($sequence)
{
$up = true;
$down = true;
foreach($sequence as $key => $item)
{
if($key > 0){
if(($item-1) != $prev) $up = false;
if(($item+1) != $prev) $down = false;
}
$prev = $item;
}
return $up || $down;
}
// areAllConsecutive([3,4,5,6]); // true
// areAllConsecutive([3,5,6,7]); // false
// areAllConsecutive([12,11,10,9]); // true
Here's an example that can check this requirement for a list of any size:
class MockNumber
{
public $number;
public function __construct($number)
{
$this->number = $number;
}
static public function IsListConsecutive(array $list)
{
$result = true;
foreach($list as $n)
{
if (isset($n_minus_one) && $n->number !== $n_minus_one->number + 1)
{
$result = false;
break;
}
$n_minus_one = $n;
}
return $result;
}
}
$list_consecutive = array(
new MockNumber(0)
,new MockNumber(1)
,new MockNumber(2)
,new MockNumber(3)
);
$list_not_consecutive = array(
new MockNumber(5)
,new MockNumber(1)
,new MockNumber(3)
,new MockNumber(2)
);
printf("list_consecutive %s consecutive\n", MockNumber::IsListConsecutive($list_consecutive) ? 'is' : 'is not');
// output: list_consecutive is consecutive
printf("list_not_consecutive %s consecutive\n", MockNumber::IsListConsecutive($list_not_consecutive) ? 'is' : 'is not');
// output: list_not_consecutive is not consecutive
If u don't wanna mess with any sorting, picking any of three numbers that are consecutive should give you:
- it either is adjacent to both the other numbers (diff1 = 1, diff2 = -1)
- the only number that is adjacent (diff = +-1) should comply the previous statement.
Test for the first condition. If it fails, test for the second one and under success, you've got your secuence; else the set doesn't comply.
Seems right to me. Hope it helps.
I think you need something like the following function (no need of arrays to store data)
<?php
function seqOfthree($entries) {
// entries has to be sorted descending on $e->number
$sequence = 0;
$lastNumber = 0;
foreach($entries as $e) {
if ($sequence==0 or ($e->number==$lastNumber-1)) {
$sequence--;
} else {
$sequence=1;
}
$lastNumber = $e->number;
if ($sequence ==3) {
// if you need the array of sequence you can obtain it easy
// return $records = range($lastNumber,$lastNumber+2);
return true;
}
}
// there isn't a sequence
return false;
}
function isConsecutive($array, $total_consecutive = 3, $consecutive_count = 1, $offset = 0) {
// if you run out of space, e.g. not enough array values left to full fill the required # of consecutive count
if ( $offset + ($total_consecutive - $consecutive_count ) > count($array) ) {
return false;
}
if ( $array[$offset] + 1 == $array[$offset + 1]) {
$consecutive_count+=1;
if ( $consecutive_count == $total_consecutive ) {
return true;
}
return isConsecutive($array, $total_consecutive, $consecutive_count, $offset+=1 );
} else {
return isConsecutive($array, $total_consecutive, 1, $offset+=1 );
}
}
The following function will return the index of the first of the consecutive elements, and false if none exist:
function findConsecutive(array $numbers)
{
for ($i = 0, $max = count($numbers) - 2; $i < $max; ++$i)
if ($numbers[$i] == $numbers[$i + 1] - 1 && $numbers[$i] == $numbers[$i + 2] - 2)
return $i;
return false;
}
Edit: This seemed to cause some confusion. Like strpos(), this function returns the position of the elements if any such exists. The position may be 0, which can evaluate to false. If you just need to see if they exist, then you can replace return $i; with return true;. You can also easily make it return the actual elements if you need to.
Edit 2: Fixed to actually find consecutive numbers.

Categories