PHP for Practical Learning: A Step-by-Step Guide to Building a Food Delivery Website Print

  • 0

PHP - Class and Object

In object-oriented PHP, a class is a blueprint for creating objects. An object, in turn, is an instantiation of a class. Let's start with a simple class for a "Restaurant".


class Restaurant {
// Member Variable
public $name;

// Member Function
public function set_name($name) {
$this->name = $name;
}

public function get_name() {
return $this->name;
}
}

To create an object from a class, we use the "new" keyword:


$restaurant = new Restaurant();
$restaurant->set_name("Big Burger");
echo $restaurant->get_name(); // Outputs: Big Burger

Inheritance: Parent Class and Child Class

Inheritance allows a class to use properties and methods of another class. Let's create a child class "FastFoodRestaurant" that inherits from our "Restaurant" class.


class FastFoodRestaurant extends Restaurant {
public $type = "Fast Food";

public function get_type() {
return $this->type;
}
}

We can create an object from our child class, and it will have access to the parent's methods:


$fastFood = new FastFoodRestaurant();
$fastFood->set_name("Speedy Pizza");
echo $fastFood->get_name(); // Outputs: Speedy Pizza
echo $fastFood->get_type(); // Outputs: Fast Food
```

Polymorphism and Overloading

Polymorphism lets us perform a single action in different ways. We can achieve this in PHP with method overloading. We'll add an overloaded method to our "FastFoodRestaurant" class.


class FastFoodRestaurant extends Restaurant {
public $type = "Fast Food";

public function get_type() {
return $this->type;
}

public function set_name($name, $owner = null) {
$this->name = $owner ? "$name by $owner" : $name;
}
}

Data Abstraction and Encapsulation

Data abstraction is a mechanism where you show only relevant data and encapsulation is wrapping data and methods as a single unit. Let's improve our class with these concepts.


class Restaurant {
// Member Variable
private $name;

// Member Function
public function set_name($name) {
$this->name = $name;
}

public function get_name() {
return $this->name;
}
}

Constructor and Destructor

The constructor and destructor methods are called when an object is created and destroyed.


class Restaurant {
private $name;

// Constructor
public function __construct($name) {
$this->name = $name;
}

// Destructor
public function __destruct() {
echo "{$this->name} is no longer in business.";
}

public function get_name() {
return $this->name;
}
}

$restaurant = new Restaurant("Big Burger");
echo $restaurant->get_name(); // Outputs: Big Burger

Access Modifiers

Access modifiers control the visibility of class properties and methods.

- Public: accessible everywhere.
- Private: only accessible within the class.
- Protected: accessible within the class and its descendants.

Abstract Classes and Interfaces

An abstract class cannot be instantiated and serves as a blueprint for child classes.


abstract class FoodDeliveryService {
abstract protected function calculateDeliveryFee($distance);
}

An interface defines a contract that implementing classes must follow.


interface OrderInterface {
public function placeOrder();
}

Constants, Static, and Final Keyword

Constants are declared using the "const" keyword and cannot be changed once defined.

Static properties and methods belong to the class, not the instance of the class.

The final keyword prevents child classes from overriding a method or prevents class from being inherited.


class Restaurant {
// Constant
const CATEGORY = 'Food';

// Static Property
public static $totalRestaurants = 0;

// Final method
final public function printCategory() {
echo self::CATEGORY;
}
}

echo Restaurant::CATEGORY; // Outputs: Food
echo Restaurant::$totalRestaurants; // Outputs: 0

As you continue building your PHP application, keep these concepts in mind, and remember, the key to learning is through consistent practice and implementation. 

Let's Continue: Fleshing Out Our Food Delivery Website with PHP OOP

Building Food and Menu Classes

Food items are the core part of any food delivery website. Let's create a simple `Food` class, and since a restaurant typically has a menu, we'll create a `Menu` class that uses `Food` objects.


class Food {
private $name;
private $price;

public function __construct($name, $price) {
$this->name = $name;
$this->price = $price;
}

public function get_name() {
return $this->name;
}

public function get_price() {
return $this->price;
}
}

class Menu {
private $items = array();

public function add_item(Food $food) {
$this->items[] = $food;
}

public function get_items() {
return $this->items;
}
}

Now, you can create a `Food` object for each dish and add it to the `Menu`.


$pizza = new Food("Pizza", 10);
$pasta = new Food("Pasta", 8);

$menu = new Menu();
$menu->add_item($pizza);
$menu->add_item($pasta);

Creating User and Order Classes

Users are crucial to any application. For simplicity, we'll create a `User` class with only essential fields: `username` and `address`.


class User {
private $username;
private $address;

public function __construct($username, $address) {
$this->username = $username;
$this->address = $address;
}

public function get_username() {
return $this->username;
}

public function get_address() {
return $this->address;
}
}

An `Order` class should contain information about the `User`, the `Food` items ordered, and the total price.


class Order {
private $user;
private $items = array();
private $totalPrice = 0;

public function __construct(User $user) {
$this->user = $user;
}

public function add_item(Food $food) {
$this->items[] = $food;
$this->totalPrice += $food->get_price();
}

public function get_items() {
return $this->items;
}

public function get_total_price() {
return $this->totalPrice;
}
}

A user can now place an order:


$user = new User("John Doe", "123 Pizza St");
$order = new Order($user);
$order->add_item($pizza);
$order->add_item($pasta);

Further Development

You can extend this basic structure to include restaurant reviews, special offers, delivery tracking, and more. While this example only scratches the surface of what PHP and OOP can do, it provides a solid foundation to further explore and expand your skills. Continue to experiment with the principles of OOP to gain a more in-depth understanding of how it can be used in PHP development.

PHP OOP in Practice: Advanced Concepts and Functionalities for a Food Delivery Website

Working with Interfaces

Interfaces are excellent tools for ensuring that certain classes contain particular methods. Let's create a `Reviewable` interface that requires a `leaveReview` function.


interface Reviewable {
public function leaveReview($username, $rating, $comment);
}

The `Restaurant` class can now implement this interface, signifying that it has a `leaveReview` method:


class Restaurant implements Reviewable {
private $reviews = array();

public function leaveReview($username, $rating, $comment) {
$this->reviews[] = array('username' => $username, 'rating' => $rating, 'comment' => $comment);
}

public function getReviews() {
return $this->reviews;
}
}

Users can now leave reviews for a restaurant:


$restaurant = new Restaurant("Big Burger");
$restaurant->leaveReview("John Doe", 5, "Great food!");

Implementing Static and Final Keywords

Static properties and methods belong to a class itself, not any specific object of the class. This can be useful for storing information relevant to all objects of the class. For example, we can count the total number of orders:


class Order {
private static $totalOrders = 0;

// Rest of the class...

public function __construct(User $user) {
$this->user = $user;
self::$totalOrders++;
}

public static function getTotalOrders() {
return self::$totalOrders;
}
}

Now every time a new order is made, the total order count increases:


$order1 = new Order($user);
$order2 = new Order($user);
echo Order::getTotalOrders(); // Outputs: 2

The `final` keyword can be used to prevent a method from being overridden in child classes, or to prevent a class from being extended. This can be useful to prevent crucial behavior from being accidentally changed.


final class Restaurant {
// This class cannot be extended
}

class FastFoodRestaurant extends Restaurant {
// This will cause an error
}

Understanding Exceptions

Exceptions are a way of handling errors in PHP, and they're integral to maintaining the robustness of your code. Here's how you can use exceptions in your food delivery website:


class Restaurant {
public function set_name($name) {
if (empty($name)) {
throw new Exception("Restaurant name can't be empty");
}
$this->name = $name;
}
}

try {
$restaurant = new Restaurant();
$restaurant->set_name("");
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}

This is just a glimpse into the capabilities of PHP and object-oriented programming. As you continue developing your food delivery website, experiment with these concepts to build robust, maintainable, and efficient code. Remember, programming is an ongoing learning process. Keep coding, exploring, and improving.

PHP OOP Deep Dive: Adding Robust Features to Your Food Delivery Website

Enhancing Reviews with Polymorphism

Since we have multiple entities like `Restaurant` and `Food` that can be reviewed, let's make use of polymorphism. Create an abstract class `ReviewableEntity` and let `Restaurant` and `Food` extend it:


abstract class ReviewableEntity {
protected $reviews = [];

public function leaveReview($username, $rating, $comment) {
$this->reviews[] = ['username' => $username, 'rating' => $rating, 'comment' => $comment];
}

public function getReviews() {
return $this->reviews;
}
}

class Restaurant extends ReviewableEntity {
// ...
}

class Food extends ReviewableEntity {
// ...
}

Now, both `Restaurant` and `Food` instances can have reviews:


$restaurant = new Restaurant("Big Burger");
$restaurant->leaveReview("John Doe", 4, "Great ambiance!");

$pizza = new Food("Pizza", 10);
$pizza->leaveReview("Jane Doe", 5, "Delicious!");

Introducing Order Status with Constants

We can use constants to represent different order statuses:


class Order {
const STATUS_PENDING = 'pending';
const STATUS_PREPARING = 'preparing';
const STATUS_OUT_FOR_DELIVERY = 'out_for_delivery';
const STATUS_DELIVERED = 'delivered';

private $status = self::STATUS_PENDING;

public function getStatus() {
return $this->status;
}

public function setStatus($status) {
$this->status = $status;
}
}

$order = new Order($user);
echo $order->getStatus(); // Outputs: pending
$order->setStatus(Order::STATUS_OUT_FOR_DELIVERY);
echo $order->getStatus(); // Outputs: out_for_delivery

Using the Singleton Pattern for a Cart

We can use the Singleton pattern to ensure that there's only one cart instance per session. Here's how to create a `Cart` class as a singleton:


class Cart {
private static $instance;
private $items = [];

private function __construct() {}

public static function getInstance() {
if (null === static::$instance) {
static::$instance = new static();
}
return static::$instance;
}

public function addItem(Food $food) {
$this->items[] = $food;
}

public function getItems() {
return $this->items;
}
}

$cart = Cart::getInstance();
$cart->addItem($pizza);

These are just a few ways you can enhance your food delivery website using OOP in PHP. Understanding and applying these principles will not only improve the quality of your code but will also equip you with the skills to tackle complex real-world programming challenges. Keep exploring and refining your knowledge to become a proficient PHP developer.

 


Was this answer helpful?

« Back