</>
CodeLearn Pro
Start Learning Free โ†’

PHP โ€” Complete Beginner Tutorial

6 modules ยท 20 examples ยท Click โ–ถ Run Code to see the console output

โœฆ Beginnerโ† Overview

๐Ÿ’ก How to use this tutorial

Read each explanation, study the code, then click โ–ถ Run Code to see the output.

Module 01

Variables & Basics

Every PHP file starts with <?php. All PHP variables start with a dollar sign ($). You do not need to declare a type โ€” PHP figures it out from the value you assign. echo prints output to the screen. PHP has four main data types you will use constantly: strings (text), integers (whole numbers), floats (decimal numbers), and booleans (true or false). Strings can use single quotes or double quotes โ€” only double quotes allow variable interpolation.

Variables and Data Types

PHP variables always start with $. You can assign any type of value to any variable โ€” PHP is dynamically typed. echo outputs text. var_dump() is the most useful debugging tool โ€” it shows both the value AND the type of a variable. Use it constantly when learning.

example.phpPHP
<?php
// String โ€” text in quotes
$name    = "Alice";
$city    = 'Cape Town';  // single quotes also work

// Integer โ€” whole number
$age     = 25;
$score   = 100;

// Float โ€” decimal number
$price   = 29.99;
$height  = 1.72;

// Boolean โ€” true or false
$is_active = true;
$is_admin  = false;

// echo โ€” print to screen
echo "Hello, $name!\n";          // variable inside double quotes
echo "Age: " . $age . "\n";     // concatenate with .
echo "City: {$city}\n";         // curly brace syntax

// var_dump โ€” shows type AND value (great for debugging)
var_dump($age);
var_dump($price);
var_dump($is_active);
var_dump($name);

// gettype โ€” just the type name
echo gettype($score) . "\n";
echo gettype($price) . "\n";
โ–ถ Click Run Code to see output

Single quotes in PHP are faster โ€” they do not look for variables to interpolate. "Hello $name" (double quotes) shows Hello Alice. 'Hello $name' (single quotes) shows Hello $name literally. Use double quotes when you want variables inside the string, single quotes when you do not.

String Operations

PHP has a rich set of built-in string functions. Strings are joined (concatenated) with the . (dot) operator, not + like in most languages. PHP has hundreds of string functions โ€” the most common are strlen, strtoupper, strtolower, str_replace, substr, trim, and explode.

example.phpPHP
<?php
$greeting = "Hello, World!";
$name     = "  Alice Smith  ";

// Basic string info
echo strlen($greeting) . "\n";          // length: 13
echo strtoupper($greeting) . "\n";      // ALL CAPS
echo strtolower($greeting) . "\n";      // all lower
echo ucfirst("hello") . "\n";           // Hello
echo ucwords("hello world") . "\n";     // Hello World

// Searching and replacing
echo str_replace("World", "PHP", $greeting) . "\n";
echo str_contains($greeting, "World") ? "found\n" : "not found\n";
echo str_starts_with($greeting, "Hello") ? "yes\n" : "no\n";

// Extracting part of a string
echo substr($greeting, 7) . "\n";       // from index 7 to end
echo substr($greeting, 7, 5) . "\n";    // 5 chars from index 7

// Trimming whitespace
echo trim($name) . "\n";               // removes both ends
echo ltrim($name) . "\n";              // left only

// Splitting and joining
$csv = "apple,banana,cherry";
$fruits = explode(",", $csv);           // split string into array
print_r($fruits);
echo implode(" | ", $fruits) . "\n";   // join array into string
โ–ถ Click Run Code to see output

explode() and implode() are two of the most used PHP string functions. explode(",", $string) splits a string by a separator into an array โ€” great for processing CSV data. implode(", ", $array) joins an array back into a string. Think of them as the opposite of each other.

Constants and Multi-line Strings

Constants are like variables but their value never changes. Define them with define() or the const keyword. A heredoc is a way to write multi-line strings without escaping quotes โ€” everything between <<<EOT and EOT is the string, including line breaks and variable interpolation.

example.phpPHP
<?php
// Constants โ€” cannot be changed after definition
define("MAX_ATTEMPTS", 3);
define("SITE_NAME", "CodeLearn Pro");
define("PI", 3.14159);

echo SITE_NAME . "\n";        // no $ sign for constants
echo "Pi = " . PI . "\n";
echo "Max: " . MAX_ATTEMPTS . "\n";

// const keyword (modern PHP)
const VERSION = "8.2";
echo "PHP " . VERSION . "\n";

// Heredoc โ€” multi-line string with interpolation
$name = "Alice";
$age  = 25;

$message = <<<EOT
Dear $name,

Welcome to CodeLearn Pro!
You are $age years old.
Your plan: Free Forever.

Regards,
The CodeLearn Team
EOT;

echo $message . "\n";

// Nowdoc โ€” multi-line string WITHOUT interpolation
$raw = <<<'EOT'
This has $name in it
But it will NOT be replaced.
EOT;

echo $raw . "\n";
โ–ถ Click Run Code to see output

Constants are a best practice for values that should never change in your application โ€” things like database table names, file paths, API keys, and configuration values. They make code easier to maintain: change the constant definition in one place and it updates everywhere it is used.

Module 02

Control Flow

PHP control flow works just like JavaScript or Java. Use if, elseif, and else to make decisions. PHP comparison operators: == (equal value), === (equal value AND type), != (not equal), !== (not equal or different type), >, <, >=, <=. Always use === for comparisons โ€” == can cause bugs because PHP tries to convert types. For example, 0 == "hello" is TRUE in PHP with ==, but false with ===.

if / elseif / else

The if statement runs code when a condition is true. elseif (one word in PHP) adds more branches. else catches everything else. PHP also has a ternary operator for short if/else in one line. The null coalescing operator ?? is very useful for providing defaults.

example.phpPHP
<?php
$score = 78;

// Standard if / elseif / else
if ($score >= 90) {
    echo "Grade: A โ€” Distinction!\n";
} elseif ($score >= 75) {
    echo "Grade: B โ€” Merit\n";
} elseif ($score >= 60) {
    echo "Grade: C โ€” Pass\n";
} elseif ($score >= 50) {
    echo "Grade: D โ€” Bare pass\n";
} else {
    echo "Grade: F โ€” Try again\n";
}

// Comparison operators
$a = 5;
$b = "5";
var_dump($a == $b);   // true  โ€” same value (loose)
var_dump($a === $b);  // false โ€” different types (strict)

// Ternary operator โ€” short if/else
$age = 20;
$status = ($age >= 18) ? "adult" : "minor";
echo "Status: $status\n";

// Null coalescing โ€” use default if null/undefined
$username = null;
echo ($username ?? "Guest") . "\n";

$username = "Alice";
echo ($username ?? "Guest") . "\n";

// Logical operators
$logged_in = true;
$is_admin  = false;

if ($logged_in && !$is_admin) {
    echo "Regular user logged in\n";
}
โ–ถ Click Run Code to see output

Always use === (triple equals) instead of == (double equals) for comparisons in PHP. PHP's == does type juggling โ€” it converts values before comparing, which leads to counterintuitive results. "0" == false is true. "0" == null is false. These surprises are avoided entirely with ===.

switch and match (PHP 8)

switch checks a variable against multiple cases. Each case needs a break to stop fall-through. match is a modern PHP 8 alternative โ€” it uses strict comparison (===), does not need break, and returns a value directly. Use match when you can โ€” it is safer and cleaner.

example.phpPHP
<?php
$day = "Wednesday";

// Traditional switch
switch ($day) {
    case "Monday":
        echo "Start of the week\n";
        break;
    case "Tuesday":
        echo "Second day\n";
        break;
    case "Wednesday":
        echo "Midweek!\n";
        break;
    case "Saturday":
    case "Sunday":
        echo "Weekend!\n";
        break;
    default:
        echo "A weekday\n";
}

// match โ€” PHP 8 (cleaner and strict)
$http_code = 404;

$message = match($http_code) {
    200, 201 => "Success",
    301, 302 => "Redirect",
    404      => "Not Found",
    500      => "Server Error",
    default  => "Unknown status",
};

echo "HTTP $http_code: $message\n";

// match with no argument โ€” works like if/elseif
$temperature = 35;

$weather = match(true) {
    $temperature < 0   => "Freezing",
    $temperature < 15  => "Cold",
    $temperature < 25  => "Mild",
    $temperature < 35  => "Warm",
    default            => "Hot",
};

echo "Weather: $weather\n";
โ–ถ Click Run Code to see output

match uses strict comparison (===) unlike switch which uses loose (==). This means match(0) will NOT match "0" or false โ€” which is the correct behaviour you want. Also, if no arm matches in match, it throws an UnhandledMatchError, forcing you to handle all cases. switch just falls through to default silently.

Module 03

Loops

PHP has four loop types: for (when you know how many iterations), while (when you keep going until a condition is false), do-while (runs at least once then checks), and foreach (designed specifically for arrays). foreach is the most important loop in PHP because arrays are used everywhere. break exits a loop early. continue skips the current iteration.

for and while Loops

The for loop has three parts in the parentheses: initialisation, condition, and increment. The while loop just has a condition โ€” it keeps running as long as the condition is true. Always make sure the condition eventually becomes false, or you get an infinite loop.

example.phpPHP
<?php
// for loop โ€” count 1 to 5
echo "Counting up: ";
for ($i = 1; $i <= 5; $i++) {
    echo "$i ";
}
echo "\n";

// for loop โ€” count down
echo "Countdown: ";
for ($i = 5; $i >= 1; $i--) {
    echo "$i ";
}
echo "\n";

// for loop โ€” step by 2
echo "Evens: ";
for ($i = 2; $i <= 10; $i += 2) {
    echo "$i ";
}
echo "\n";

// while loop
$count = 1;
$total = 0;
while ($count <= 10) {
    $total += $count;
    $count++;
}
echo "Sum 1-10: $total\n";

// do-while โ€” runs AT LEAST once
$num = 1;
do {
    echo "do-while: $num\n";
    $num++;
} while ($num <= 3);

// break and continue
echo "Skip 3 and stop at 7: ";
for ($i = 1; $i <= 10; $i++) {
    if ($i === 3) continue;   // skip 3
    if ($i === 7) break;      // stop at 7
    echo "$i ";
}
echo "\n";
โ–ถ Click Run Code to see output

$i++ is shorthand for $i = $i + 1. PHP also has $i-- (subtract 1), $i += 5 (add 5), $i *= 2 (multiply by 2). These compound assignment operators work on any variable type โ€” strings, arrays, etc. โ€” and are standard in all PHP code you will encounter.

foreach โ€” The Array Loop

foreach is designed specifically for looping over arrays. For indexed arrays, it gives you each value. For associative arrays (key-value pairs), it gives you both the key and the value using the => syntax. foreach is the most common loop you will write in PHP.

example.phpPHP
<?php
// foreach over indexed array
$fruits = ["apple", "banana", "cherry", "mango"];

foreach ($fruits as $fruit) {
    echo "- $fruit\n";
}

echo "---\n";

// foreach with index (key => value)
foreach ($fruits as $index => $fruit) {
    echo "$index. $fruit\n";
}

echo "---\n";

// foreach over associative array
$person = [
    "name"  => "Alice",
    "age"   => 25,
    "city"  => "Cape Town",
    "skill" => "PHP",
];

foreach ($person as $key => $value) {
    echo ucfirst($key) . ": $value\n";
}

echo "---\n";

// Modifying array values with & (reference)
$prices = [10.0, 25.0, 5.0, 40.0];
foreach ($prices as &$price) {
    $price = $price * 1.15;  // add 15% VAT
}
unset($price);  // important: unset the reference

foreach ($prices as $p) {
    echo "R" . number_format($p, 2) . "\n";
}
โ–ถ Click Run Code to see output

When you use & in foreach ($items as &$item), you get a reference to the actual array element, not a copy. This lets you modify the original array. After the loop, always unset($item) to break the reference โ€” if you forget, the last element can be overwritten accidentally if you reuse the variable name later.

Module 04

Functions

Functions in PHP are defined with the function keyword. PHP 8 added type declarations โ€” you can specify what type each parameter should be and what type the function returns. This catches bugs early. PHP also supports default parameter values, returning multiple values using arrays, and anonymous functions (closures) which can be passed to other functions like array_map and array_filter.

Defining and Calling Functions

Write the function keyword, then the function name, then parameters in parentheses. PHP 8 type declarations (string $name, int $age): string are highly recommended โ€” they catch type errors before they cause mysterious bugs. Functions return a value with return, or return nothing (void).

example.phpPHP
<?php
// Basic function
function say_hello(): void {
    echo "Hello, World!\n";
}

say_hello();

// Function with typed parameters and return type
function greet(string $name, string $greeting = "Hello"): string {
    return "$greeting, $name!";
}

echo greet("Alice") . "\n";
echo greet("Bob", "Good morning") . "\n";

// Function returning a number
function add(int $a, int $b): int {
    return $a + $b;
}

echo add(15, 27) . "\n";

// Function with conditional return
function grade(int $score): string {
    if ($score >= 90) return "A";
    if ($score >= 75) return "B";
    if ($score >= 60) return "C";
    if ($score >= 50) return "D";
    return "F";
}

echo "Score 85 = " . grade(85) . "\n";
echo "Score 55 = " . grade(55) . "\n";
echo "Score 30 = " . grade(30) . "\n";

// Multiple return values (via array)
function min_max(array $numbers): array {
    return [min($numbers), max($numbers)];
}

[$low, $high] = min_max([3, 1, 9, 2, 7]);
echo "Min: $low, Max: $high\n";
โ–ถ Click Run Code to see output

PHP type declarations (string $name): string are optional but strongly recommended. Without them, PHP silently converts types โ€” passing "25" where you expect an integer just works, which hides bugs. With strict_types=1 at the top of your file, PHP enforces types strictly and will throw a TypeError on mismatches.

Anonymous Functions and Arrow Functions

An anonymous function (closure) is a function without a name โ€” assigned to a variable or passed directly to another function. PHP 7.4 added arrow functions using fn() => which are shorter and automatically capture variables from the surrounding scope.

example.phpPHP
<?php
// Anonymous function assigned to a variable
$shout = function(string $text): string {
    return strtoupper($text) . "!!!";
};

echo $shout("hello") . "\n";

// Passing a function to another function
$numbers = [3, 1, 4, 1, 5, 9, 2, 6];

// array_map โ€” transform every element
$doubled = array_map(function($n) { return $n * 2; }, $numbers);
echo implode(", ", $doubled) . "\n";

// array_filter โ€” keep matching elements
$evens = array_filter($numbers, function($n) { return $n % 2 === 0; });
echo implode(", ", $evens) . "\n";

// Arrow functions (PHP 7.4+) โ€” much shorter!
$squared = array_map(fn($n) => $n ** 2, $numbers);
echo implode(", ", $squared) . "\n";

$big = array_filter($numbers, fn($n) => $n > 4);
echo implode(", ", $big) . "\n";

// Arrow functions capture outer scope automatically
$multiplier = 3;
$tripled = array_map(fn($n) => $n * $multiplier, [1, 2, 3, 4, 5]);
echo implode(", ", $tripled) . "\n";
โ–ถ Click Run Code to see output

Arrow functions (fn($x) => $x * 2) automatically capture variables from the surrounding scope. Regular anonymous functions need use ($variable) to access outer variables: function($x) use ($multiplier) { return $x * $multiplier; }. For short transformations passed to array_map/filter, always prefer arrow functions โ€” they are much cleaner.

Module 05

Arrays

PHP arrays are one of the most powerful and flexible data structures in any language. A PHP array can be indexed (0, 1, 2...), associative (key => value), or nested (arrays inside arrays). PHP has over 70 built-in array functions. The most important ones are array_map, array_filter, array_reduce, usort, array_merge, array_keys, array_values, in_array, and array_search.

Indexed and Associative Arrays

An indexed array uses automatic numeric keys starting from 0. An associative array uses custom string or integer keys. Both are created with [] or array(). The [] syntax is preferred in modern PHP. Use print_r() to display an array in a readable format during development.

example.phpPHP
<?php
// Indexed array โ€” automatic keys 0, 1, 2...
$fruits = ["apple", "banana", "cherry"];

echo $fruits[0] . "\n";          // first element
echo $fruits[count($fruits) - 1] . "\n";  // last element

// Adding elements
$fruits[] = "mango";              // append
array_push($fruits, "grape");     // also append
array_unshift($fruits, "avocado"); // add to front

echo "Total: " . count($fruits) . "\n";
print_r($fruits);

// Removing elements
$removed = array_pop($fruits);    // remove from end
echo "Removed: $removed\n";

// Associative array โ€” custom keys
$person = [
    "name"  => "Alice",
    "age"   => 25,
    "email" => "alice@example.com",
    "city"  => "Cape Town",
];

echo $person["name"] . "\n";
echo $person["city"] . "\n";

// Updating a value
$person["age"] = 26;

// Check if key exists
if (array_key_exists("email", $person)) {
    echo "Email: " . $person["email"] . "\n";
}

// Get all keys and values
echo implode(", ", array_keys($person)) . "\n";
echo implode(", ", array_values($person)) . "\n";
โ–ถ Click Run Code to see output

Use $array[] = $value to append to an array โ€” it is shorter than array_push() and works the same way. array_unshift() adds to the beginning but is slower than appending because PHP has to reindex all elements. For large arrays that need frequent additions at the start, consider reversing your approach.

Essential Array Functions

PHP has dozens of built-in array functions. The functional ones โ€” array_map, array_filter, array_reduce โ€” are the most powerful. usort lets you sort by any custom rule. array_merge combines arrays. in_array checks if a value exists. array_unique removes duplicates.

example.phpPHP
<?php
$numbers = [5, 2, 8, 1, 9, 3, 7, 4, 6];

// Sorting
sort($numbers);
echo "Sorted: " . implode(", ", $numbers) . "\n";

rsort($numbers);
echo "Reversed: " . implode(", ", $numbers) . "\n";

// array_map โ€” transform every element
$squared = array_map(fn($n) => $n ** 2, $numbers);
echo "Squared: " . implode(", ", $squared) . "\n";

// array_filter โ€” keep matching (reindexes with array_values)
$evens = array_values(array_filter($numbers, fn($n) => $n % 2 === 0));
echo "Evens: " . implode(", ", $evens) . "\n";

// array_reduce โ€” combine into one value
$total = array_reduce($numbers, fn($carry, $n) => $carry + $n, 0);
echo "Sum: $total\n";

// Searching
echo in_array(7, $numbers) ? "7 found\n" : "7 not found\n";
echo array_search(7, $numbers) . " (index of 7)\n";

// Merging and slicing
$a = [1, 2, 3];
$b = [4, 5, 6];
$merged = array_merge($a, $b);
echo implode(", ", $merged) . "\n";

$slice = array_slice($merged, 2, 3);  // start at 2, take 3
echo implode(", ", $slice) . "\n";

// Unique values
$dupes = [1, 2, 2, 3, 3, 3, 4];
echo implode(", ", array_unique($dupes)) . "\n";
โ–ถ Click Run Code to see output

array_filter does not reindex numeric keys โ€” if element 2 is removed, you get keys 0, 1, 3, 4. Wrap it in array_values() to reset to 0, 1, 2, 3. This is a very common PHP gotcha. For associative arrays with string keys, this is not an issue since the keys are meaningful anyway.

Module 06

Classes & OOP

Object-oriented PHP uses classes to group related data and functions together. A class is a blueprint โ€” you create objects from it using new. The __construct() method runs when an object is created. Properties hold the object's data. Methods are the object's functions. Visibility (public, private, protected) controls who can access what. PHP 8 introduced constructor property promotion which drastically reduces boilerplate code.

Classes, Properties and Methods

Define a class with class. Use __construct() for the constructor. Properties start with public, private, or protected. Access properties and methods on an object with -> (arrow). PHP 8 constructor property promotion lets you declare and assign properties right in the constructor parameters.

example.phpPHP
<?php
class BankAccount {
    // PHP 8 constructor promotion โ€” declare and assign in one go
    public function __construct(
        public readonly string $id,
        public string $owner,
        private float $balance = 0.0,
    ) {}

    // Method โ€” deposit money
    public function deposit(float $amount): void {
        if ($amount <= 0) {
            echo "Amount must be positive\n";
            return;
        }
        $this->balance += $amount;
        echo "Deposited R$amount. Balance: R{$this->balance}\n";
    }

    // Method โ€” withdraw money
    public function withdraw(float $amount): void {
        if ($amount > $this->balance) {
            echo "Insufficient funds\n";
            return;
        }
        $this->balance -= $amount;
        echo "Withdrew R$amount. Balance: R{$this->balance}\n";
    }

    // Getter โ€” read private balance
    public function getBalance(): string {
        return "R" . number_format($this->balance, 2);
    }

    // Magic method โ€” called when object used as string
    public function __toString(): string {
        return "Account({$this->id}, {$this->owner})";
    }
}

$account = new BankAccount("ACC001", "Alice");
echo $account . "\n";          // calls __toString
echo $account->owner . "\n";   // public property

$account->deposit(1000);
$account->deposit(500);
$account->withdraw(200);
$account->withdraw(5000);       // will fail

echo "Balance: " . $account->getBalance() . "\n";
โ–ถ Click Run Code to see output

PHP 8 constructor promotion (public string $owner in the __construct parameters) automatically creates the property AND assigns the parameter value to it. This replaces the old pattern of declaring $public string $owner; separately and then writing $this->owner = $owner; in the constructor body. It saves a lot of repetitive code.

Inheritance and Interfaces

A child class extends a parent class using extends โ€” it inherits all public and protected properties and methods. Override parent methods by redefining them. Call the parent version with parent::methodName(). Interfaces define a contract โ€” any class that implements an interface must have all the interface's methods.

example.phpPHP
<?php
// Interface โ€” defines a contract
interface Describable {
    public function describe(): string;
}

// Base class
class Shape implements Describable {
    public function __construct(
        public readonly string $color = "black"
    ) {}

    public function area(): float {
        return 0.0;
    }

    public function describe(): string {
        return "A {$this->color} shape with area " . $this->area();
    }
}

// Child class
class Circle extends Shape {
    public function __construct(
        public readonly float $radius,
        string $color = "red",
    ) {
        parent::__construct($color);
    }

    public function area(): float {
        return round(M_PI * $this->radius ** 2, 2);
    }
}

class Rectangle extends Shape {
    public function __construct(
        public readonly float $width,
        public readonly float $height,
        string $color = "blue",
    ) {
        parent::__construct($color);
    }

    public function area(): float {
        return $this->width * $this->height;
    }
}

$circle = new Circle(5);
$rect   = new Rectangle(4, 6);

echo $circle->describe() . "\n";
echo $rect->describe() . "\n";

// Polymorphism
$shapes = [$circle, $rect, new Circle(3, "green")];
foreach ($shapes as $shape) {
    echo get_class($shape) . ": area = " . $shape->area() . "\n";
}
โ–ถ Click Run Code to see output

Interfaces in PHP are not just for documentation โ€” they enable dependency injection and testability. When a function accepts an interface type instead of a concrete class, you can pass any class that implements that interface. This is the "program to an interface, not an implementation" principle and is core to professional PHP architecture.

You finished the PHP tutorial!

You can now write PHP with variables, control flow, loops, functions, arrays and classes. You have the foundation to start learning Laravel and building real web applications with forms, databases and authentication.