Skip to content

PHP Tutorial Modern PHP Features Exercise

Practice: Modernise Old PHP Code

Lesson 238 of 369 2 min read By Deepak Paswan Updated Oct 5, 2026

Here is a class written in an old style. Your job is to rewrite it with modern PHP. Try it first, then compare.

The old code

index.php
PHP
<?php
class Order
{
    var $id;
    var $status;
    var $items;

    function Order($id, $items)
    {
        $this->id = $id;
        $this->items = $items;
        $this->status = "pending";
    }

    function total()
    {
        $t = 0;
        foreach ($this->items as $i) {
            $t = $t + $i["price"] * $i["qty"];
        }
        return $t;
    }

    function statusLabel()
    {
        switch ($this->status) {
            case "pending":
                return "Waiting";
            case "paid":
                return "Paid";
            default:
                return "Unknown";
        }
    }
}

What is wrong with it

  • var and untyped properties, and an old-style constructor name.
  • No types on parameters or return values.
  • Public data anyone can change.
  • A status as a free string: "piad" would be accepted silently.
  • switch with loose comparison.

Exercise: rewrite it

Rewrite the class in modern PHP. Use declare(strict_types=1), an enum for the status, a constructor with promoted readonly or private properties, types everywhere, array_reduce() or array_sum(), and match for the label.

Show a possible solution
index.php
PHP
<?php
declare(strict_types=1);

enum OrderStatus: string
{
    case Pending = "pending";
    case Paid = "paid";

    public function label(): string
    {
        return match ($this) {
            self::Pending => "Waiting",
            self::Paid => "Paid",
        };
    }
}

final class Order
{
    /**
     * @param array<int, array{price: float, qty: int}> $items
     */
    public function __construct(
        public readonly int $id,
        private array $items,
        private OrderStatus $status = OrderStatus::Pending,
    ) {}

    public function total(): float
    {
        return array_reduce(
            $this->items,
            fn(float $sum, array $item): float => $sum + $item["price"] * $item["qty"],
            0.0
        );
    }

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

    public function markPaid(): void
    {
        $this->status = OrderStatus::Paid;
    }
}

$order = new Order(7, [
    ["price" => 12.0, "qty" => 5],
    ["price" => 250.0, "qty" => 2],
]);

echo $order->total() . " " . $order->status()->label() . "\n";

$order->markPaid();

echo $order->status()->label();
Output
OUTPUT
560 Waiting
Paid

What changed

OldModern
var $id;A promoted public readonly int $id
Constructor named after the class__construct()
Free string statusOrderStatus enum
switchmatch on the enum
A manual looparray_reduce()
No typesTypes on every parameter, property and return

Exercise 2: spot the PHP 8 features

Look at the finished class. List at least six features that did not exist in PHP 7.0.

Show the answer

Constructor property promotion (8.0), readonly properties (8.1), enums (8.1), match (8.0), trailing commas in parameter lists (8.0), the : string backed enum (8.1), and readonly with promotion (8.1). Typed properties (7.4) and arrow functions (7.4) arrived earlier in PHP 7.4.