Error found on simple php code, "Parsing error" [duplicate] - php

This question already has answers here:
PHP parse/syntax errors; and how to solve them
(20 answers)
Reference - What does this error mean in PHP?
(38 answers)
Closed 3 years ago.
Parse error: syntax error, unexpected 'public' (T_PUBLIC), expecting end of file in C:\xampp\htdocs\example.php on line 9
I'm getting this error, but can't see nothing wrong with the code.
What did I wrong? Won't return the expected results.
The program is supposed to show: echo $myorder->OrderTotal();
<?php
class CartEntry
{
//changing to private
private $Price;
private $Quantity;
}
//Adding functions to get price and quantity,
public function __construct($Price, $Quantity)
{
$this->Price = $Price;
$this->Quantity = $Quantity;
}
public function ReturnPrice() {
return $this->Price;
}
public function ReturnQuantity() {
return $this->Quantity;
}
}
//
class CartContents
{
//Changed to private
private $items = array();
}
//Adding function to return items, same as above
public function __construct($items) {
$this->items = $items;
}
public function ReturnItems() {
return $this->items;
}
}
class Order
{
private $cart;
private $salesTax;
//cartcontents function removed
function __construct( float $salesTax, Array $items){
$this->salesTax = $salesTax;
$this->items = $items;
}
function OrderTotal()
{
$cartTotal = 0;
for ($i = 0; $i < count($this->items); $i++) {
$cartTotal += $this->items[$i]->Price * $this->items[$i]->Quantity;
}
$cartTotal += $cartTotal * $this->salesTax;
return $cartTotal;
}
}
$entry1 = new CartEntry();
$entry1->Price = 1.2;
$entry1->Quantity = 120;
$entry2 = new CartEntry();
$entry2->Price = 2.2;
$entry2->Quantity = 200;
$mycart = new CartContents();
$mycart->items = array($entry1, $entry2);
$items = $mycart->ReturnItems();
$mytax = 0.2;
//Items variable can be changed with mycart
$myorder = new Order($items, $mytax);
echo $myorder->OrderTotal();
?>

Here is the corrected code:
<?php
class CartEntry
{
//changing to private
private $Price;
private $Quantity;
public function __construct($Price, $Quantity)
{
$this->Price = $Price;
$this->Quantity = $Quantity;
}
public function ReturnPrice() {
return $this->Price;
}
public function ReturnQuantity() {
return $this->Quantity;
}
}// end class
class CartContents
{
//Changed to private
private $items = array();
public function __construct($items) {
$this->items = $items;
}
public function ReturnItems() {
return $this->items;
}
} // end class
class Order
{
private $cart;
private $salesTax;
function __construct( float $salesTax, Array $items){
$this->salesTax = $salesTax;
$this->items = $items;
}
function OrderTotal()
{
$cartTotal = 0;
for ($i=0, $max=count($this->items); $i < $max; $i++) {
$cartTotal += $this->items[$i]->ReturnPrice() * $this->items[$i]->ReturnQuantity();
}
$cartTotal += $cartTotal * $this->salesTax;
return $cartTotal;
}
}
$entry1 = new CartEntry(1.2, 120);
$entry2 = new CartEntry(2.2,200);
$mycart = new CartContents([$entry1,$entry2]);
$items = $mycart->ReturnItems();
$mytax = 0.2;
//Items variable can be changed with mycart
$myorder = new Order($mytax,$items);
echo $myorder->OrderTotal();
See live code.
One should avoid putting a brace after declaring class properties if the class has methods; that's what caused the error message that the OP encountered. As per the online Manual:
... class definitions begin with the keyword class, followed by a
class name, followed by a pair of curly braces which enclose the
definitions of the properties and methods (emphasis mine) belonging to the class.
Don't let the term 'function' fool you. If it's in a class it is a method; see this discussion.
But after fixing that issue there were others.
If you are suppose to initialize properties in a constructor, then you need to pass in the correct parameters when you instantiate an object, instead of trying to set those properties as if they were public.
Note, also that when an object has methods for reading private properties then you need to use those methods instead of trying to access the private properties directly.
Lastly, I changed this line of code
for ($i=0; $i < count($this->items); $i++) which executes correctly but it is more efficient to count the items just once instead of doing it on every iteration, so I inserted instead:
for ($i=0, $max=count($this->items); $i < $max; $i++){

You should put all your methods inside the class. In your code, the class CartEntry only contains 2 private variables:
class CartEntry
{
//changing to private
private $Price;
private $Quantity;
}
Anything outside the class will be considered invalid.

Related

How to sum the array of ingredient?

I am trying to implement the getCost() function using a forloop but i am new to php and having trouble with understanding how to implement. i just keep getting error saying undefined variable.
Here is my code
<?php
class Burger {
public $title = '';
private $ingredients = array();
public function __construct($n) {
$this->name = $n;
}
public function addIngredient($ing) {
array_push($this->ingredients, $ing);
}
public function getCost() {
foreach( $ingredients as $ingredient=> $costDollars){
$price += $costDollars;
return $price;
}
} }
class Ingredient {
public $name = 'Ingredient'; public $costDollars = 0.0;
public function __construct($n, $c) {
$this->name = $n;
$this->costDollars = $c;
} }
$myBurger = new Burger('Tasty Burger');
$myBurger->addIngredient(new Ingredient('Meat', 0.3));
$myBurger->addIngredient(new Ingredient('Cheese', 0.2));
$myBurger->addIngredient(new Ingredient('Beetroot', 0.2));
$myBurger->addIngredient(new Ingredient('Pineapple', 0.4));
echo $myBurger->getCost(); ?>
You're forgetting $this when you're trying to access the class property $ingredients:
public function getCost() {
$price = 0;
foreach( $this->ingredients as $ingredient){
$price += $ingredient->costDollars;
}
return $price;
}
As you can see in the above code, the return-statement is also moved after the loop. If you have the return in your loop, the variable will be returned after the first iteration.
<?php
class Burger {
public $title = '';
private $ingredients = array();
public function __construct($n) {
$this->name = $n;
}
public function addIngredient($ing, $cost) {
$this->ingredients += array($ing => $cost); // Wont overide! EXTRA CHEEZ PLZ
}
public function getCost() {
//forloop
$totalprice = 0; // Start Register Cha Ching!
foreach($this->ingredients as $ing => $price){ // Add Items (*scanner Beeps*
$totalprice += $price;
} // All Done with items, let return cost
return $totalprice; // Return Value to Function Call
}
}
$myBurger = new Burger('Tasty Burger');
$myBurger->addIngredient('Meat', 0.3);
$myBurger->addIngredient('Cheese', 0.2);
$myBurger->addIngredient('Beetroot', 0.2);
$myBurger->addIngredient('Pineapple', 0.4);
echo $myBurger->getCost(); ?> // ECHO Value to Function Call

Poor Man's Session ID Causes Parse Error

I created this little guy to get large session IDs for my own purposes:
// returns a 1024-byte hash for session IDs
class sha512_session {
private $IDvalue = '';
private $IDMAX_SALT = mt_getrandmax();
for ($i = 0; $i < 8; $i++) {
$seed = mt_rand(100, $IDMAX_SALT);
$IDvalue .= strtoupper(hash('sha512', $seed, false));
}
public function getID() {
return $IDvalue;
}
}
Outside of a class context, the for() loop works like it should. When I put this (working) code in the class above, PHP returns the following:
Parse error: syntax error, unexpected '(', expecting ',' or ';' in ../sha-iterator.php on line ... ( line # for "private $IDMAX_SALT = mt_getrandmax()" )
So, it works fine outside a class and breaks inside a class. Where did I mess up?
The For loop must be placed within a function. I think you should place it in a constructor.
class sha512_session {
private $IDvalue = '';
private $IDMAX_SALT;
function __construct() {
$this->IDMAX_SALT = mt_getrandmax();
for ($i = 0; $i < 8; $i++) {
$this->seed = mt_rand(100, $this->IDMAX_SALT);
$this->IDvalue .= strtoupper(hash('sha512', $this->seed, false));
}
}
public function getID() {
return $this->IDvalue;
}
}
Ok a comment on here answered my question. Class property initialization during declaration must be a constant at compile time, but mt_getrandmax() is runtime info, so it fails. The correct way here is to declare the variable, then initialize it separately:
class sha512_session {
private $IDvalue = '';
private $IDMAX_SALT;
private function getRandomMax() {
$this->IDMAX_SALT = mt_getrandmax();
return $this->IDMAX_SALT;
}
function __construct() {
for ($i = 0; $i < 8; $i++) {
$this->seed = mt_rand(100, $this->getRandomMax());
$this->IDvalue .= strtoupper(hash('sha512', $this->seed, false));
}
}
public function getID() {
return $this->IDvalue;
}
}
$sessionID = new sha512_session();
echo $sessionID->getID();
Or any variation on that theme.

PHP Private Variable issue

I try to get value of a private variable (limit), but I get the following error:
Fatal error: Uncaught Error: Using $this when not in object context in /home/vagrant/Code/wp/wp-content/plugins/StorePress/app/library/Pagination.php on line 36
My Class:
class Pagination
{
private $limit = 0;
private $limit_start = 0;
private $total = 0;
/**
* Generate Pagination for Products
* #param $pagination
* #return string
*/
public function __constructor($pagination = null)
{
$this->limit = $pagination['limit'];
$this->lim_start = ($pagination['start']) ?: null;
$this->total = $pagination['total'];
}
public function generatePagination()
{
echo $this->limit;
}
Here, I'm trying to print "$this->limit", a private variable, but it's not allowed to print the value that are assigned by the "__constructor".
Is there anything wrong in my code or is there any other solution to get that value?
I think, that the problem is in your OOP construction. You cannot echo $this private variable, when you don't create class object as first. So the solution might be:
class Pagination
{
private $limit = 0;
private $limit_start = 0;
private $total = 0;
/**
* Generate Pagination for Products
* #param $pagination
* #return string
*/
public function __constructor($pagination = null)
{
$this->limit = $pagination['limit'];
$this->lim_start = ($pagination['start']) ?: null;
$this->total = $pagination['total'];
}
public function generatePagination()
{
return $this->limit;
}
and then in your code, where you need to echo the limit value, you can use:
$pagination = new Pagination();
echo $pagination->generatePagination();
At first line, you will create new Pagination() object and in the second line, you will return the $limit value from your generatePagination class function.
Shouldn't your keyword __constructor be __construct instead according to this link

I would like to know how to keep an inventory variable in a class the same for all new objects?

The problem am having is keeping my inventory variable keep up with the changes made by different objects. For example, the $me object buys 4 items, which deducts from the inventory and leaves 6 in the inventory that is good. Then I make a new object $l, but the inventory starts from 10 again, instead of the new current inventory of 6.
Below is my PHP code for my class
class cashRegister {
public $total = 0;
public $name;
public $discount;
public $lastamount;
public $inventory = 10;
public function __construct($name, $discount) {
$this->name = $name;
$this->discount = $discount;
}
public function add($itemCost) {
$this->total += $itemCost;
$this->lastamount = $itemCost;
}
public function scan($item, $quantity) {
switch ($item) {
case "eggs" :
$this->add ( 1 * $quantity);
$this->inventory($quantity);
break;
case "news" :
$this->add(2 * $quantity);
$this->inventory($quantity);
}
//$this->inventory -= $quantity;
}
public function inventory($quantity) {
$this->inventory -= $quantity;
}
public function staffDiscount() {
$this->total -= ($this->total * ($this->discount/100)) ;
}
public function voidL() {
$this->total -= $this->lastamount;
}
}
Below is my normal code
include 'cashRegister.php';
$me = new cashRegister("Mg", 20);
$l = new cashRegister("ll", 50);
echo $me->inventory;
$me->scan("eggs", 2);
$me->scan("eggs", 1);
$me->scan("news", 1);
//$me->staffDiscount();
echo $me->inventory;
//echo $l->inventory;
//echo $me->total;
When you create a new instance of a class (that happens whenever you use the keyword new) it will create a brand new kind of 'copy' or 'instance' of that class. So, when you subtract the inventory amount, you are only subtracting from that instance.
PHP has the keyword static that will change the public instance variable of $inventory into a kind of shared variable between all instances of that class.
Update it from public to static to look like this:
public static $inventory = 10;
But you also need several other changes because you cannot reference a static variable in the same way as an instance variable.
Basically you need to change $this-> to self:: in your inventory method:
public function inventory($quantity) {
self::$inventory -= $quantity;
}
Then when you reference the static variable from the instance variable you need to access it like this:
echo $me::$inventory;
Your final code would look like this:
<?
class cashRegister {
public $total = 0;
public $name;
public $discount;
public $lastamount;
public static $inventory = 10;
public function __construct($name, $discount) {
$this->name = $name;
$this->discount = $discount;
}
public function add($itemCost) {
$this->total += $itemCost;
$this->lastamount = $itemCost;
}
public function scan($item, $quantity) {
switch ($item) {
case "eggs" :
$this->add ( 1 * $quantity);
$this->inventory($quantity);
break;
case "news" :
$this->add(2 * $quantity);
$this->inventory($quantity);
}
//$this->inventory -= $quantity;
}
public function inventory($quantity) {
self::$inventory -= $quantity;
}
public function staffDiscount() {
$this->total -= ($this->total * ($this->discount/100)) ;
}
public function voidL() {
$this->total -= $this->lastamount;
}
}
And when you call it:
$me = new cashRegister("Mg", 20);
$l = new cashRegister("ll", 50);
echo $me::$inventory;
echo "<br>";
$me->scan("eggs", 2);
$me->scan("eggs", 1);
$me->scan("news", 1);
//$me->staffDiscount();
echo $me::$inventory;
//echo $l->inventory;
//echo $me->total;
Here is an updated class that gives you a more extended idea of how you can use objects.
Instead of just an inventory class, it breaks down an item into an individual class and object that you can use.
When an item is scanned it loops through the inventory items and if there is not enough of that item in stock it will return false - in a real world scenario, you would probably handle that error differently but for this case it is okay. You might add a method called 'isItemInStock()' to the Inventory class that will check if it is available first.
So now that the inventory is an object its instance is shared between the other objects as well as the items that are in stock. Instead of adding/subtracting the totals during the scan process there is a getTotal() method that will recalculate the total with the discount.
<?
class Item {
public $name;
public $cost;
public $quantity;
public function __construct($name, $cost, $quantity=null) {
$this->name = $name;
$this->cost = $cost;
$this->quantity = $quantity;
}
}
class Inventory
{
public $items = array();
public function __construct()
{
}
public function add($item) {
$this->items[] = $item;
}
}
class CashRegister {
public $name;
public $discount;
public $inventory;
public $items = array();
public function __construct($name, $discount, $inventory) {
$this->name = $name;
$this->discount = $discount;
$this->inventory = $inventory;
}
public function add($item) {
$this->items[] = $item;
}
public function scan( $name, $qty ) {
foreach ($this->inventory->items as $key => $item) {
if ($item->name==$name) {
if (($item->quantity-$qty)>=0) {
$this->inventory->items[$key]->quantity -= $qty;
$this->add( new Item($item->name, $item->cost, $qty) );
return true;
} else {
// Not added, not enough
return false;
}
}
}
// Invalid item
return false;
}
public function getTotal() {
$total = 0;
foreach ($this->items as $item) {
$total += $item->cost*$item->quantity;
}
$discount = ((100-$this->discount)/100);
echo "Discount total: $discount\n";
return $total - $discount;
}
}
$inventory = new Inventory();
$inventory->add( new Item('eggs', 1, 20) );
$inventory->add( new Item('news', 2, 50) );
$cb1 = new CashRegister(1, 20, $inventory );
echo "<pre>\n";
echo "Scanning 5 eggs\n";
$cb1->scan( 'eggs', 5);
foreach ($inventory->items as $item) {
echo $item->name . ': '. $item->quantity." in stock\n";
}
echo "Scanning 6 news\n";
$cb1->scan( 'news', 5);
foreach ($inventory->items as $item) {
echo $item->name . ': '. $item->quantity." in stock\n";
}
$cb2 = new CashRegister(2, 30, $inventory );
echo "Scanning 3 eggs\n";
$cb2->scan('eggs', 3);
foreach ($inventory->items as $item) {
echo $item->name . ': '. $item->quantity." in stock\n";
}
echo "Cash Register 1 Total: " . $cb1->getTotal() . "\n";
echo "Cash Register 2 Total: " . $cb2->getTotal() . "\n";
I would define your inventory separately and add it to your cash register invocation.
class Inventory
{
public $eggs;
public $news;
public function __construct($eggs = 10, $news = 10)
{
$this->eggs = $eggs;
$this->news = $news;
}
}
You would need to modify your CashRegister class to use the properties of the object rather than just modifying the inventory property, and accept the inventory as an argument.
class CashRegister
{
// ...
protected $inventory;
public function __construct($inventory, name, $discount)
{
$this->inventory = $inventory;
$this->name = $name;
$this->discount = $discount;
}
// ...
public function scan($item, $quantity)
{
switch ($item) {
case "eggs" :
$this->add ( 1 * $quantity);
$this->inventory($item, $quantity);
break;
case "news" :
$this->add(2 * $quantity);
$this->inventory($item, $quantity);
}
}
protected function inventory($item, $quantity)
{
$this->inventory->$item -= $quantity;
}
// ...
}
Then you can do something like this:
$inventory = new Inventory;
$me = new CashRegister($inventory, 'mg', 20);
$l = new CashRegister($inventory, 'l', 50);
// ...
Because objects are always passed by reference, your inventory object is now in sync between both registers, and the changes made in either will affect the available inventory.

Calling method on all instances of class

I am looking for a way to call a function on all instances of a class preferably via a static method call.
Example:
class number{
private $number;
static function addAll(){
//add all of the values from each instance together
}
function __construct($number){
$this->number = $number;
}
}
$one = new number(1);
$five = new number(5);
//Expecting $sum to be 6
$sum = number::addAll();
Any help on this would be greatly appreciated. Thanks!
It can be done like this:
class MyClass {
protected $number;
protected static $instances = array();
public function __construct($number) {
// store a reference of every created object
static::$instances [spl_object_hash($this)]= $this;
$this->number = $number;
}
public function __destruct() {
// don't forget to remove objects if they are destructed
unset(static::$instances [spl_object_hash($this)]);
}
/**
* Returns the number. Not necessary here, just because
* you asked for an object method call in the headline
* question.
*/
public function number() {
return $this->number;
}
/**
* Get's the sum from all instances
*/
public static function sumAll() {
$sum = 0;
// call function for each instance
foreach(static::$instances as $hash => $i) {
$sum += $i->number();
}
return $sum;
}
}

Categories