Language lab · Beginner → Web
🐘 PHP
Concept → trace → write code → run tests → explain why → improve → mini-project. Start in the browser if you like; set up your own computer when you are ready.
📖 Topics with real code (16)
Every verified output below was produced by running the code with PHP 8.3.36 (cli) (built: Nov 5 2026 07:26:18) (NTS) on 5 Nov 2026. Open a topic to edit the code and run it on our isolated compile server (sign in needed).
🌱 Beginner (5)
Variables and data types
Variables start with $. Types: int, float, bool, string, array, null. var_dump shows type and value; casts like (int) convert. declare(strict_types=1) makes function type checks strict.
<?php $age = 15; $height = 1.62; $isStudent = true; $name = "Asha"; $nothing = null; echo "$name $age $height ", var_export($isStudent, true), "\n"; var_dump($age, $height, $isStudent, $nothing); echo gettype($name), " ", (int) "88" + 2, " ", intdiv(7, 2), " ", 7 / 2, " ", (int) 9.99, "\n"; echo PHP_INT_MAX, "\n";
✅ Verified output
Asha 15 1.62 true int(15) float(1.62) bool(true) NULL string 90 3 3.5 9 9223372036854775807
Operators and boolean logic
Use === (same value and type) rather than ==. . joins strings, ** is power, % remainder, ?? gives a default for null, <=> compares three ways.
<?php $a = 17; $b = 5; echo $a + $b, " ", $a - $b, " ", $a * $b, " ", $a / $b, " ", intdiv($a, $b), " ", $a % $b, " ", $a ** 2, "\n"; var_dump(5 == "5", 5 === "5", "abc" == 0); $hasTicket = true; $isVip = false; echo "enter: ", var_export($hasTicket && !$isVip, true), "\n"; $nick = null; echo $nick ?? "no nickname", " | ", 1 <=> 2, " ", 2 <=> 2, "\n"; echo "Gaya" . "Gnan", "\n";
✅ Verified output
22 12 85 3.4 3 2 289 bool(true) bool(false) bool(false) enter: true no nickname | -1 0 GayaGnan
Conditionals: if, match
if/elseif/else picks a branch. match (PHP 8) is a strict, value-returning switch with no fall-through.
<?php
$marks = 78;
if ($marks >= 90) $grade = "A+";
elseif ($marks >= 75) $grade = "A";
elseif ($marks >= 35) $grade = "Pass";
else $grade = "Fail";
echo "Grade: $grade\n";
$day = "sat";
echo match ($day) {
"sat", "sun" => "Weekend",
default => "School day",
}, "\n";
echo $marks >= 35 ? "passed" : "try again", "\n";
✅ Verified output
Grade: A Weekend passed
Loops: for, while, foreach
foreach is the usual way to walk arrays (with keys if needed). break and continue control loops.
<?php
for ($i = 1; $i <= 5; $i++) {
if ($i === 3) continue;
echo "for $i\n";
}
$n = 10;
while ($n > 0) {
if ($n < 4) break;
echo "while $n\n";
$n -= 3;
}
foreach (["red", "green"] as $i => $colour) echo "foreach $i $colour\n";
for ($r = 1; $r <= 3; $r++) {
for ($c = 1; $c <= 3; $c++) printf("%3d", $r * $c);
echo "\n";
}
✅ Verified output
for 1 for 2 for 4 for 5 while 10 while 7 while 4 foreach 0 red foreach 1 green 1 2 3 2 4 6 3 6 9
Functions and type declarations
Functions can declare parameter and return types, default values, named arguments and variadic parameters.
<?php
declare(strict_types=1);
function area(int $length, int $width = 1): int {
return $length * $width;
}
function average(int ...$nums): float {
return array_sum($nums) / count($nums);
}
function greet(string $name, string $greeting = "Namaste"): string {
return "$greeting, $name!";
}
echo area(5, 3), " ", area(7), " ", average(4, 9, 2, 7), "\n";
echo greet(greeting: "Hello", name: "Meena"), "\n";
try {
area("5", 3);
} catch (TypeError $e) {
echo "TypeError with strict types\n";
}
✅ Verified output
15 7 5.5 Hello, Meena! TypeError with strict types
🌿 Intermediate (7)
Indexed arrays
PHP arrays are ordered maps. Indexed arrays use 0,1,2... array_map, array_filter and sort transform them.
<?php
$marks = [72, 95, 64, 88];
$marks[] = 91;
sort($marks);
echo implode(", ", $marks), " | first {$marks[0]} last ", end($marks), " count ", count($marks), "\n";
$odd = array_filter(range(1, 5), fn($x) => $x % 2 === 1);
$squares = array_map(fn($x) => $x * $x, $odd);
echo implode(" ", $squares), " sum ", array_sum($squares), "\n";
[$first, $second] = $marks;
echo "$first $second\n";
print_r(array_slice($marks, -2));
✅ Verified output
64, 72, 88, 91, 95 | first 64 last 95 count 5
1 9 25 sum 35
64 72
Array
(
[0] => 91
[1] => 95
)
Strings
Double quotes interpolate variables; single quotes do not. Useful functions: strlen, strtoupper, str_replace, explode, implode, sprintf, str_contains. mb_ functions handle Unicode correctly.
<?php
$t = trim(" GayaGnan learning ");
echo strtoupper($t), " | ", str_replace("learning", "labs", $t), " | ", strlen($t), "\n";
$words = explode(" ", $t);
echo implode("-", $words), " contains Gnan: ", var_export(str_contains($t, "Gnan"), true), "\n";
echo sprintf("Total: ₹%.2f for %d items", 49.5 * 3, 3), "\n";
$s = "నమస్తే";
echo "bytes ", strlen($s), " characters ", mb_strlen($s), "\n";
echo 'single: $t', " | palindrome: ", var_export("level" === strrev("level"), true), "\n";
✅ Verified output
GAYAGNAN LEARNING | GayaGnan labs | 17 GayaGnan-learning contains Gnan: true Total: ₹148.50 for 3 items bytes 18 characters 6 single: $t | palindrome: true
Associative arrays
Keys can be strings. ksort sorts by key; array_key_exists checks a key; array_count_values counts items.
<?php
$stock = ["pen" => 40, "book" => 12];
$stock["eraser"] = 25;
$stock["pen"] -= 5;
ksort($stock);
foreach ($stock as $item => $count) echo "$item $count\n";
echo "has ruler? ", var_export(array_key_exists("ruler", $stock), true), "\n";
$freq = array_count_values(explode(" ", "the cat and the hat and the bat"));
ksort($freq);
print_r($freq);
echo json_encode(["name" => "Asha", "marks" => [88, 92]]), "\n";
✅ Verified output
book 12
eraser 25
pen 35
has ruler? false
Array
(
[and] => 2
[bat] => 1
[cat] => 1
[hat] => 1
[the] => 3
)
{"name":"Asha","marks":[88,92]}
Classes and constructor promotion
Classes have typed properties and methods. Constructor promotion (PHP 8) declares and assigns properties in the constructor signature; readonly fields cannot change.
<?php
class BankAccount {
public function __construct(public readonly string $owner, private float $balance = 0) {}
public function deposit(float $amount): void {
if ($amount <= 0) throw new InvalidArgumentException("amount must be positive");
$this->balance += $amount;
}
public function balance(): float { return $this->balance; }
}
$acc = new BankAccount("Asha", 500);
$acc->deposit(250);
echo $acc->owner, " ", $acc->balance(), "\n";
try {
$acc->owner = "x";
} catch (Error $e) {
echo "readonly: ", get_class($e), "\n";
}
✅ Verified output
Asha 750 readonly: Error
Interfaces, inheritance and polymorphism
An interface is a contract; abstract classes share code; subclasses override methods. instanceof checks the type.
<?php
interface Shape { public function area(): float; }
abstract class Base implements Shape {
public function describe(): string { return static::class . " " . number_format($this->area(), 2); }
}
class Circle extends Base { public function __construct(private float $r) {} public function area(): float { return M_PI * $this->r ** 2; } }
class Rect extends Base { public function __construct(private float $w, private float $h) {} public function area(): float { return $this->w * $this->h; } }
foreach ([new Circle(1), new Rect(3, 4)] as $s) echo $s->describe(), " ", var_export($s instanceof Shape, true), "\n";
✅ Verified output
Circle 3.14 true Rect 12.00 true
Exceptions
try/catch/finally handles errors. Catch several types with |. Custom exceptions extend Exception.
<?php
class InsufficientFunds extends Exception {}
function withdraw(float $balance, float $amount): float {
if ($amount > $balance) throw new InsufficientFunds("need " . ($amount - $balance) . " more");
return $balance - $amount;
}
try {
echo intdiv(10, 0);
} catch (DivisionByZeroError $e) {
echo "DivisionByZeroError: ", $e->getMessage(), "\n";
} finally {
echo "finally always runs\n";
}
try {
withdraw(100, 150);
} catch (InsufficientFunds | TypeError $e) {
echo get_class($e), ": ", $e->getMessage(), "\n";
}
✅ Verified output
DivisionByZeroError: Division by zero finally always runs InsufficientFunds: need 50 more
Files and CSV
file_put_contents and file_get_contents handle whole files; fgetcsv reads CSV rows. sys_get_temp_dir gives the temp folder.
<?php
$path = tempnam(sys_get_temp_dir(), "marks");
file_put_contents($path, "name,marks\nAsha,88\nRavi,95\n");
$f = fopen($path, "r");
fgetcsv($f, escape: "\\");
$total = 0; $count = 0;
while (($row = fgetcsv($f, escape: "\\")) !== false) {
echo "$row[0] -> $row[1]\n";
$total += (int) $row[1];
$count++;
}
fclose($f);
unlink($path);
echo "average ", $total / $count, "\n";
✅ Verified output
Asha -> 88 Ravi -> 95 average 91.5
🌳 Advanced (4)
Recursion and memoization
A static array inside the function keeps the cache between calls. PHP ints are 64-bit, enough for fib(80).
<?php
function fib(int $n): int {
static $memo = [];
if ($n < 2) return $n;
return $memo[$n] ??= fib($n - 1) + fib($n - 2);
}
function binarySearch(array $a, int $t, int $lo, int $hi): int {
if ($lo > $hi) return -1;
$mid = intdiv($lo + $hi, 2);
if ($a[$mid] === $t) return $mid;
return $a[$mid] < $t ? binarySearch($a, $t, $mid + 1, $hi) : binarySearch($a, $t, $lo, $mid - 1);
}
echo implode(" ", array_map('fib', range(0, 9))), " | fib(80) = ", fib(80), "\n";
$a = [2, 5, 8, 12, 16, 23, 38];
echo "index of 23: ", binarySearch($a, 23, 0, count($a) - 1), "\n";
✅ Verified output
0 1 1 2 3 5 8 13 21 34 | fib(80) = 23416728348467685 index of 23: 5
Closures, arrow functions and callables
Closures can capture variables with use (by value or &reference). Arrow functions fn() capture automatically. usort takes a comparison callable.
<?php
function makeCounter(): Closure {
$n = 0;
return function () use (&$n) { return ++$n; };
}
$c = makeCounter();
$c(); $c();
echo "count ", $c(), "\n";
$applyTwice = fn(callable $f, $x) => $f($f($x));
echo $applyTwice(fn($n) => $n * 3, 2), " ", $applyTwice('strtoupper', "hi"), "\n";
$students = [["Asha", 88], ["Ravi", 95], ["Meena", 72]];
usort($students, fn($a, $b) => $b[1] <=> $a[1]);
echo implode(", ", array_column($students, 0)), "\n";
✅ Verified output
count 3 18 HI Ravi, Asha, Meena
Generators and Fibers
A generator yields values one at a time, so a large sequence never sits in memory. Fibers (PHP 8.1) pause and resume code: the base for async libraries.
<?php
function evens(int $limit): Generator {
for ($i = 0; $i <= $limit; $i += 2) yield $i;
}
$sum = 0;
foreach (evens(1_000_000) as $e) $sum += $e;
echo "sum of evens ", $sum, ", memory stays small\n";
$fiber = new Fiber(function (string $task): string {
echo "start $task\n";
$got = Fiber::suspend("paused at step 1");
echo "resumed with $got\n";
return "done $task";
});
echo $fiber->start("download"), "\n";
$fiber->resume("data");
echo $fiber->getReturn(), "\n";
✅ Verified output
sum of evens 250000500000, memory stays small start download paused at step 1 resumed with data done download
Copy-on-write and references
Arrays are copied on assignment (copy-on-write keeps it cheap); objects are handles, so two variables can share one object. & makes a reference to the same variable.
<?php
$a = [1, 2];
$b = $a; // copy
$b[] = 3;
echo "a ", implode(",", $a), " b ", implode(",", $b), "\n";
$o1 = new stdClass();
$o1->x = 1;
$o2 = $o1; // same object
$o2->x = 99;
echo "objects share: ", $o1->x, "\n";
$o3 = clone $o1;
$o3->x = 5;
echo "clone is separate: ", $o1->x, " ", $o3->x, "\n";
function addMark(array &$list): void { $list[] = 100; }
addMark($a);
echo "by reference: ", implode(",", $a), "\n";
✅ Verified output
a 1,2 b 1,2,3 objects share: 99 clone is separate: 99 5 by reference: 1,2,100
🛠️ Set up and verify
- Install
winget install PHP.PHP.8.3
brew install php
sudo apt install php-cli php-sqlite3
- Editor: Visual Studio Code with PHP Intelephense, PHP Debug.
- Create
hello.php<?php echo "Hello, GayaGnan!\n";
- Run it and check the version
php hello.php php --version
- Health check: paste what your terminal printed.
Install one language at a time. These commands only install or print versions; nothing here deletes files. Versions change: check the official page and note the version you installed.
🧭 The 14-lab path
- 00 · Setup and verify — install the runtime and editor, run hello world, print the version, fix PATH
- 01 · Syntax and trace — follow each line and the value of every variable
- 02 · Logic — conditionals and decision trees
- 03 · Loops — trace tables and loop challenges
- 04 · Functions — break problems down and test each piece
- 05 · Data structures — lists, maps, stacks, queues and trees you can see
- 06 · Debugging — bug cases with a hint ladder
- 07 · Algorithms — search, sort and Big-O comparison
- 08 · Files and data — read and write fixture files
- 09 · API or database — talk to a mock API or a sandbox database
- 10 · Testing — write tests and read failing assertions
- 11 · Security — secure coding and dependency hygiene for this language
- 12 · Project — one portfolio mini-project
- 13 · Assessment — quiz, coding test, rubric and an explain-your-answer prompt
📚 Modules
- syntax
- arrays
- functions
- forms
- validation
- sessions
- PDO
- SQL safety
- Composer
- MVC concepts
- REST
- tests
- environment config
🏗️ Mini-projects
- Course enrolment mock portal
- Catalogue API
- Login flow with local test identities (never real credentials)
Projects use synthetic data only.