Checkpoint: PHP Basics

Reviewed & published by Brayan K

You've learned data types, strings, numbers, type juggling, constants, superglobals and null operators — let's combine them. This checkpoint is one build that exercises everything from the section at once, plus a quiz to confirm it all stuck.

Part of the free PHP course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

What You've Learned

Eight types; the everyday five (string, int, float, bool, null); the falsy seven; get_debug_type.

Interpolation, trim, str_contains, substr, explode/implode, mb_*.

%, **, round/ceil/floor, number_format, the float trap.

Implicit juggling vs explicit casts, == vs ===, strict_types, filter_var.

const vs define, array & class constants, magic constants, global scope.

$_GET/$_POST/$_SERVER, validate-then-escape, ??, ??=, ?->.

The Build: Order Receipt Generator

Here's the brief. You're handed form-style input where every value is a string and one field (coupon) is missing entirely. Your job is to read it safely, validate the numbers, do the money math with a constant tax rate, and print a clean receipt. This single script touches every topic from PHP Basics. Start from the starter below; only reveal the solution once you've genuinely attempted it.

Compare this against your own attempt. The key moves: ?? defaults every read, filter_var validates the numeric strings (returning false on failure, which is why we test with === false), constants hold the tax rate and currency, and number_format formats the money for display only.

<?php
declare(strict_types=1);

$_POST = [
    'name'  => '  ada lovelace  ',
    'qty'   => '3',
    'price' => '19.99',
];

const TAX_RATE = 0.20;
const CURRENCY = '$';

// 1. NAME — default, trim, title-case.
$name = ucwords(trim($_POST['name'] ?? 'guest'));

// 2. QTY — validate, fall back to 1.
$qty = filter_var($_POST['qty'] ?? '', FILTER_VALIDATE_INT);
if ($qty === false) { $qty = 1; }

// 3. PRICE — validate, fall back to 0.0.
$price = filter_var($_POST['price'] ?? '', FILTER_VALIDATE_FLOAT);
if ($price === false) { $price = 0.0; }

// 4. COUPON — null means no discount.
$coupon = $_POST['coupon'] ?? null;
$discount = $coupon === null ? 0.0 : 5.0;

// 5. MATH
$subtotal = $qty * $price;
$subtotal -= $discount;
$tax = $subtotal * TAX_RATE;
$total = $subtotal + $tax;

// 6. OUTPUT
echo "Customer: $name\n";
echo "Items:    $qty x " . CURRENCY . number_format($price, 2) . "\n";
echo "Subtotal: " . CURRENCY . number_format($subtotal, 2) . "\n";
echo "Tax 20%:  " . CURRENCY . number_format($tax, 2) . "\n";
echo "Total:    " . CURRENCY . number_format($total, 2) . "\n";
?>

📝 Checkpoint Quiz

Six questions spanning the whole section. Predict each answer first, then reveal it. If any surprise you, revisit the linked lesson — that's exactly what checkpoints are for.

float(5). The / operator always returns a float, even for whole results. Use intdiv(10, 2) if you need int(5). (See Numbers.)

Only "0.0" is truthy — it's a non-empty string that isn't exactly "0". The other three are all in the falsy seven. (See Data Types.)

?? prints 0 (it only replaces null). ?: would print none because 0 is falsy. (See Null Operators.)

It throws a TypeError — strict types refuse to silently juggle the string into an int. (See Type Juggling.)

Because it's untrusted user input; echoing it raw enables XSS. Wrap output in htmlspecialchars() so injected markup renders as harmless text. (See Superglobals.)

Yes to reading — constants are global by nature. No to reassigning — a constant is write-once; redefining it is a fatal error. (See Constants.)

Pro Tips for the Build

Stuck on the Build?

Receipt totals are off by a few cents? Remember floats aren't exact — for a learning exercise number_format(..., 2) rounds the display cleanly; in production you'd work in integer cents.

"Undefined array key 'coupon'"? You read it without ??. Use $_POST['coupon'] ?? null.

Name shows lower-case? Chain the calls in the right order: ucwords(trim(...)) — trim first, then title-case.

🎉 Checkpoint Complete!

Practice quiz

What does var_dump(10 / 2) print in PHP?

  • int(5)
  • string("5")
  • float(5)
  • 5.0

Answer: float(5). The / operator always returns a float, even for whole results. Use intdiv(10, 2) when you need int(5).

Which of these values is truthy in PHP: 0, "0", "0.0", or []?

  • "0.0"
  • 0
  • "0"
  • []

Answer: "0.0". "0.0" is a non-empty string that is not exactly "0", so it is truthy. The other three are all in the falsy seven.

Given $count = 0; echo $count ?? "none"; what prints?

  • none
  • an empty string
  • null
  • 0

Answer: 0. ?? only replaces null, and 0 is not null, so it prints 0. The ?: operator would print "none" because 0 is falsy.

With declare(strict_types=1), passing the string "10" to a function expecting int does what?

  • Silently converts it to 10
  • Throws a TypeError
  • Returns null
  • Rounds it to 10.0

Answer: Throws a TypeError. Strict types refuse to coerce the string into an int, so a TypeError is thrown rather than juggling silently.

Why must you wrap $_GET data in htmlspecialchars() before echoing it into HTML?

  • To prevent XSS from untrusted input
  • To speed up output
  • To convert it to UTF-8
  • PHP requires it for all strings

Answer: To prevent XSS from untrusted input. Superglobal input is untrusted; echoing it raw enables XSS. htmlspecialchars() renders injected markup as harmless text.

Can you reassign a top-level constant defined with const after it is set?

  • Yes, like any variable
  • Only inside a function
  • No, a constant is write-once and redefining it is a fatal error
  • Only with global

Answer: No, a constant is write-once and redefining it is a fatal error. Constants are write-once. Reading them anywhere works (they are global), but redefining one is a fatal error.

After $x = filter_var($v, FILTER_VALIDATE_INT), how should you test for failure?

  • if (!$x)
  • if ($x === false)
  • if ($x == 0)
  • if (is_null($x))

Answer: if ($x === false). filter_var returns false on failure. Test with === false, because a valid 0 is falsy but is not a failure.

Which produces "Ada Lovelace" from the raw string " ada lovelace "?

  • trim(ucwords($s))
  • strtoupper(trim($s))
  • ucfirst($s)
  • ucwords(trim($s))

Answer: ucwords(trim($s)). Trim first to remove the surrounding spaces, then ucwords() title-cases each word: ucwords(trim($s)).

What does number_format(59.97, 2) return?

  • 59.97 as a float
  • "59.97"
  • "60"
  • "59.970"

Answer: "59.97". number_format returns a formatted string with the given decimal places, used for display only, not for the math.

How do you safely read a possibly-missing key, e.g. $_POST["coupon"], defaulting to null?

  • $_POST["coupon"]
  • $_POST["coupon"] ?: null
  • $_POST["coupon"] ?? null
  • isset($_POST["coupon"])

Answer: $_POST["coupon"] ?? null. The null coalescing operator $_POST["coupon"] ?? null returns null when the key is missing, avoiding an undefined-key warning.

Continue this course

Related lessons