Class based PHP tool to calculate change?

Hi. So I’m trying to learn classes and how to use them with PHP and I’m stuck. I’m trying to make a script that takes
input from a user of 2 amounts and stores them into variables. I would
then like to use these variables in a couple of functions to make some
calculations and finally echo my findings. I’m close but I’ve still got
issues and it seems like I’m now running in circles.

I’ve been reading documentation on classes and googling, but I’m quite stuck. I’m hoping for perhaps some
explanations. I could do what I need to do in just another php
processing script. But I’m really trying to learn classes and how they
can be used with other pages and how general they can be. Here’s what I
got so far:

CalculateChange.php

http://pastebin.com/ctdkYjXc#

class_Change.php

1 - Usually there is no need to have any HTML in class definition file. All the tags in your class_Change.php are useless, because you don’t want them to be printed anywhere. So remove them and let class file contain only class definition.

2 - When you do var_dump($amountOwed) you get nothing because there is no variable with that name in current scope. But, you have such property (field) in your class. And you even have a getter for it. When you declare properties (variables) inside your class like that:

class myClass { public $foo = 'bar'; }

you can access value through object of that class:

$myObject = new myClass(); 
echo $myObject->foo; // prints "bar"

But in your case all the properties are private. That means they won’t be accessible directly. Private properties visible only inside the class definition. This is why you should use getter - special function that will return private value for you:

class myClass { 
    private $foo = 'bar'; 
    public function getFoo() { return $this->foo; }
}

usage:

$myObject = new myClass();
echo $myObject->foo; //error, because this property is private
echo $myObject->getFoo(); // prints "bar"

In your class these fields are private:

private $amountOwed;
private $amountPaid;

so you can dump them using getters you already have:

var_dump($CalcChange->getOwed());
var_dump($CalcChange->getPaid());
3 Likes

Right. So, I see this. And it appears my current revision has my set functions working because

var_dump($CalcChange->getOwed());
var_dump($CalcChange->getPaid());

After submission the values are correct. Now the next issue is with change. My change variables aren’t working properly. And I think its like you said, due to my scope because I need to use them later.

$changeDue is meant to be an overall storage of the change. This variable doesn’t get modified, as its just for me to display how much total change is due for the transaction.

$change is meant to be modified through calculations to determine how many of each denomination. When it hits 0, all denominations are accounted for.

After this:

$changeDue = $this->amountPaid - $this->amountOwed;
$change = $this->amountPaid - $this->amountOwed;

$changeDue is var_dump’d as null.
$change is 0.

How can I fix $changeDue and expand the scope so that they can be used further down the program?

If you want some variable to be available in each method (function) of class and outside the class (in object) you should define that variable as a property and then use it with $this.

So I guess you have to fix these lines:

to:

$this->changeDue = $this->amountPaid - $this->amountOwed;
$this->change = $this->amountPaid - $this->amountOwed;
1 Like

Let me explain it a bit more. When you call any variable inside class method without $this you actually create a new local variable available only inside current method but not the others.

Example:

class myClass {

    private $foo = "bar";

    public function myMethod(){
        $foo = "something";
        echo $foo; // prints "something"
        echo $this->foo; // prints "bar"
    }

    public function otherMethod(){
        echo $foo; // error, there is no local variable $foo
        echo $this->foo; // prints "bar", because property available in any method
    }

}

You see in this example $foo and $this->foo are different variables.

1 Like

You might want to look at your validatePaid() method too. You are doing more than just validating. You are also calculating.

The method might look better like this (notice I also changed the name a bit):

 public function isValidPaid() {
     if ($this->getPaid() < $this->getOwed()) {
         echo "<p>The amount paid is less than the cost. Make sure the item is paid for!</p>\n";
         return false;
    }
    if ($this->getPaid() == $this->getOwed()) {
        echo "<p>They paid for the item in an exact amount. No change necessary!</p>\n";
        return false; 
   }
   return true;
}

And thus, your calculateChange() method would start out like this:

   public function calculateChange() {
       if ( $this->isValidPaid() ) {
           $changeDue = $this->amountPaid - $this->amountOwed;
           $change = $this->amountPaid - $this->amountOwed;
            // the rest of the method.....

Scott

1 Like

Interesting. I’ve done this,

When I enter again, it takes a long while to load and I get 3 errors:

Undefined variable on change and twenty on lines 76 and 77, and “Maximum execution time of 120 seconds exceeded” on line 77. Lines 76 and 77 are:

$change -= 20;
$twenty += 1;

As its part of that long list of while statements for denominations. Is this caused because $change is not $this->change? I use $this->change in the while() statement, but not in the actual body.

So, wouldn’t this mean that the class-wide variable of change doesn’t actually change because the while() checks it, but the body of while() just uses the local variable? Is my logic correct on that?

Absolutely. You check for one variable but modify another. This is the reason why you get infinite loop and your script is reaches time limit.

1 Like

Megazoid explained the basic issue (and why you are getting errors) in this post above.

Scott

1 Like

Very informative. I see why it didn’t work, and I modified it and tested it and the script appears to run correctly. The only piece of the puzzle that I’m missing is a small printing issue.

I have this text string that uses one of the variables (changeDue). Is there a function that will let me make sure that that variable always displays with 2 decimal places, while keeping the rest of the string in tact?

Use number_format:

echo number_format($changeDue, 2);
1 Like

I don’t mean to sound brash with what I am about to say, but a Google search “PHP number formatting” would have been faster than writing that post. :wink:

Scott

You want to remove the logic of validation from your class.

In your setter function pass in the data to the method so you can assign it to your internal properties.

public function setOwed( $amt )
{
    $this->amountOwed = $amt;
}

In your validatePaid() method remove the method calls in the if statements. Your using unnecessary method calls when you can access the variable data internally in the class.

In your calculateChange() method use one loop and decrement the change amount

while( $this->change >= 0 )
{
// processing logic here and decrement $this->change here
// set flag variables here could use an array 
}

Lastly remove the html code in the class. You want to use the class to process the data not do both. Separate the concerns.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.