Interesting Facts About PHP You Must Know

PHP powers a massive chunk of the internet and has been doing so for over three decades. Most developers use it daily without knowing its backstory, its quirks, or the surprising places it shows up. Here are the facts worth knowing.


1. PHP Was Never Meant to Be a Programming Language

PHP was created in 1994 by Rasmus Lerdorf — not to build a language, but to track visitors on his personal homepage. He wrote a handful of CGI scripts in C and called the collection "Personal Home Page Tools". That's where the name PHP came from.

It was never designed. It grew organically out of necessity. Lerdorf himself has said publicly:

"I don't know how to stop it, there was never any intent to write a programming language."

What started as a visitor counter eventually became the language running a third of the internet.


2. PHP No Longer Stands for What It Used to

The original meaning was Personal Home Page. As the language grew into something far beyond personal pages, the name was officially rebranded to a recursive acronym:

PHP: Hypertext Preprocessor

A recursive acronym means the abbreviation references itself in its own expansion — PHP stands for PHP Hypertext Preprocessor. It's a tradition in the programming world, borrowing from GNU (GNU's Not Unix).


3. WordPress, Facebook, and Wikipedia All Run on PHP

Some of the most visited websites in the world were built on PHP:

  • WordPress — powers over 43% of all websites on the internet, written entirely in PHP
  • Facebook — was built on PHP and still uses a heavily modified version today
  • Wikipedia — runs on MediaWiki, a PHP application
  • Slack — originally built with PHP on the backend

Facebook's usage grew so large that they built HipHop for PHP (HPHPc), a transpiler that converted PHP to C++ for performance. They later built HHVM (HipHop Virtual Machine) as a full PHP runtime alternative.


4. Facebook Built Their Own PHP Compiler

Standard PHP wasn't fast enough for Facebook's scale. So they built HHVM — a JIT-compiled runtime for PHP that dramatically improved execution speed. They also created Hack, a PHP-derived language with strict static typing, which Facebook's codebase runs on today.

The fact that a company at Facebook's scale invested that heavily in PHP infrastructure instead of rewriting everything is a testament to how deeply PHP was embedded in their systems.


5. PHP 6 Never Existed

PHP's version history goes:

PHP 5 → PHP 7 → PHP 8

PHP 6 was an ambitious project started around 2005 with a primary goal of native Unicode support. The project ran for years, faced enormous technical challenges with Unicode string handling, and was eventually abandoned in 2010.

So much of the PHP 6 work that was actually completed got backported into PHP 5.3 instead. The version number 6 was permanently skipped to avoid confusion with all the documentation, books, and articles that had already been written about the abandoned PHP 6 features.


6. PHP 7 Was a Massive Performance Leap

When PHP 7 released in December 2015, it wasn't just an incremental update. Benchmarks showed:

  • 2x faster than PHP 5.6 on most workloads
  • 50% lower memory consumption
  • Performance comparable to HHVM in many scenarios

This came from a complete internal rewrite of PHP's data structures and execution engine called phpng (PHP Next Generation). PHP 7 made a lot of "PHP is slow" arguments obsolete overnight.


7. PHP 8 Introduced a JIT Compiler

PHP 8.0 released in November 2020 and brought a Just-In-Time (JIT) compiler to PHP for the first time. JIT compiles code to native machine instructions at runtime instead of interpreting bytecode — the same concept that makes modern JavaScript engines fast.

PHP 8 also introduced:

  • Named argumentsarray_slice(array: $arr, offset: 1)
  • Match expressions — a stricter, cleaner switch
  • Nullsafe operator$user?->getAddress()?->getCity()
  • Union typesfunction foo(int|string $value)
  • Attributes — native annotation syntax replacing PHPDoc

PHP 8 was arguably the most significant modernization of the language since PHP 5.


8. PHP Has a Type System — It Just Doesn't Force You to Use It

PHP started as a loosely typed language where variables had no declared types. But since PHP 7, a full type system has been progressively added:

<?php

declare(strict_types=1);

function calculateTotal(int $quantity, float $price): float
{
    return $quantity * $price;
}

With declare(strict_types=1) at the top of a file, PHP enforces types strictly — passing the wrong type throws a TypeError. Without it, PHP coerces types silently.

PHP 8.x continues expanding the type system with intersection types, enum types, readonly properties, and never return types. Modern PHP code can be as strictly typed as TypeScript if you choose to write it that way.


9. The $ Variable Syntax Comes From Perl

PHP borrowed heavily from Perl in its early days, including the $ prefix for all variables. Perl was the dominant server-side scripting language when PHP was being built, and Rasmus Lerdorf was familiar with it.

$name = "Gagan";
$age = 25;
$isActive = true;

Every variable in PHP regardless of type uses $. It's one of the most immediately recognizable things about PHP syntax and it comes directly from Perl's influence.


10. PHP Has a Built-In Web Server

Since PHP 5.4, PHP ships with a built-in development web server — no Apache or Nginx needed for local development:

php -S localhost:8000

Point it at a directory and it serves files immediately. Laravel's php artisan serve command uses this exact built-in server under the hood.

It's not meant for production — it's single-threaded and handles one request at a time — but for local development and quick prototyping it's perfectly capable.


11. echo is Not a Function

This catches a lot of developers off guard. echo in PHP is a language construct, not a function:

echo "Hello";
echo("Hello");

Both work, but echo doesn't have a return value and can't be used as an expression. This is why you can't do:

$result = echo "Hello";

Same applies to print, isset, unset, list, array, and require — all language constructs, not functions, even though some of them look exactly like function calls.


12. PHP Arrays Are Actually Ordered Hash Maps

In most languages, arrays and hash maps (dictionaries/objects) are completely separate data structures. In PHP, there is only one data structure — the array — and it handles both:

$indexed = [1, 2, 3];

$associative = [
    'name' => 'Gagan',
    'role' => 'developer',
];

$mixed = [
    0 => 'first',
    'key' => 'value',
    1 => 'second',
];

Under the hood, every PHP array is an ordered hash map that maintains insertion order. This is different from JavaScript objects (which lost order in older specs) and Python dicts (which only guaranteed order from Python 3.7). PHP arrays have always maintained order, always.


13. Composer Changed PHP Development Completely

Before Composer launched in 2012, PHP had no standard dependency manager. Developers manually downloaded libraries, managed include paths, and dealt with version conflicts by hand. PEAR existed but was notoriously difficult to use.

Composer brought semantic versioning, a central package repository (Packagist), autoloading via PSR-4, and proper dependency resolution to PHP. It's the single biggest tooling improvement in PHP's history. Modern PHP development — Laravel, Symfony, everything — is completely built on top of Composer.


14. PHP Runs on 78% of Websites With a Known Server-Side Language

According to W3Techs data, PHP is used by 78.1% of all websites whose server-side language is known. The next closest is ASP.NET at around 6%. No other server-side language is even close in terms of deployment footprint.

This isn't because PHP is the best language by every metric — it's because it's been around long enough, is easy to host, and powers WordPress, which alone accounts for a huge portion of that number.


15. PHP's Mascot is an Elephant Named ElePHPant

Since 2007, PHP's official mascot has been the ElePHPant — a blue elephant with the PHP logo on its side. It was designed by Vincent Pontier.

The name is a portmanteau of elephant and PHP. Physical plush ElePHPant toys have been produced in multiple colors over the years and are considered collector's items in the PHP community. Different colors were produced for specific conferences, companies, and framework communities — Laravel has its own red version, Symfony has its own, and so on.


The Bottom Line

PHP has a strange history — born as a personal project, abandoned more than once, declared dead repeatedly, and yet still running the majority of the web three decades later. It's been through bad API design decisions, a cancelled major version, a complete internal rewrite, and a JIT revolution. Understanding where it came from and how it evolved makes you a better PHP developer — because a lot of the language's quirks make complete sense once you know the story behind them.

Setting Up and Configuring a Laravel Development Environment in VS Code

Before writing a single line of Laravel code, your machine needs a few things in place. This guide walks through everything from scratch — PHP, Composer, Laravel itself, and VS Code configuration — so your environment is clean, professional, and ready for real development.


What You Need Before Starting

Tool Purpose
PHP 8.2+ Laravel 11 requires PHP 8.2 minimum
Composer PHP's package manager — installs Laravel and dependencies
VS Code Your editor
XAMPP or standalone PHP Provides PHP and MySQL locally
Node.js + npm For frontend asset compilation (Vite)

Step 1 — PHP Setup

If you have XAMPP, PHP is already installed. Just make sure it's in your PATH as covered earlier. Verify in terminal:

php --version

Expected:

PHP 8.2.x (cli)

If your XAMPP ships with an older PHP version, download a newer standalone PHP from windows.php.net/download and point your PATH to that instead.


Step 2 — Install Composer

Composer is non-negotiable for Laravel. It manages every dependency the framework needs.

Windows

Download and run the installer from:

https://getcomposer.org/Composer-Setup.exe

The installer automatically adds Composer to your PATH.

macOS / Linux

php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php composer-setup.php
sudo mv composer.phar /usr/local/bin/composer

Verify installation:

composer --version
Composer version 2.7.x

Step 3 — Install Laravel

Option A — Via Laravel Installer (Recommended)

composer global require laravel/installer

After installation, create a new project:

laravel new my-project

During setup, Laravel 11 will ask you a few questions:

Which starter kit would you like to install?
> No starter kit

Which testing framework do you prefer?
> Pest

Would you like to initialize a Git repository?
> Yes

For a clean backend-focused setup, choose no starter kit.

Option B — Via Composer Directly

composer create-project laravel/laravel my-project

Both approaches produce the same result. Option A is faster for repeated use.


Step 4 — Open Project in VS Code

cd my-project
code .

Your project structure will look like this:

my-project/
├── app/
│   ├── Http/
│   │   ├── Controllers/
│   │   └── Middleware/
│   └── Models/
├── bootstrap/
├── config/
├── database/
│   ├── migrations/
│   └── seeders/
├── public/
├── resources/
│   ├── views/
│   └── js/
├── routes/
│   ├── web.php
│   └── api.php
├── storage/
├── tests/
├── .env
├── artisan
├── composer.json
└── vite.config.js

Step 5 — Configure the .env File

The .env file controls your entire local environment — database, mail, cache, and more. Open it and configure the database section:

APP_NAME=MyProject
APP_ENV=local
APP_KEY=base64:...
APP_DEBUG=true
APP_URL=http://localhost:8000

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=my_project
DB_USERNAME=root
DB_PASSWORD=

For XAMPP, the default MySQL username is root with no password. Create the database manually via phpMyAdmin or terminal:

mysql -u root -e "CREATE DATABASE my_project;"

Step 6 — Run Migrations

Once the database is created and .env is configured:

php artisan migrate
INFO  Running migrations.

  2014_10_12_000000_create_users_table ............. 12ms DONE
  2014_10_12_100000_create_password_reset_tokens_table .. 8ms DONE
  2019_08_19_000000_create_failed_jobs_table ........ 6ms DONE
  2024_01_01_000000_create_cache_table .............. 5ms DONE

Laravel's default migrations are now applied to your database.


Step 7 — Start the Development Server

php artisan serve
INFO  Server running on [http://127.0.0.1:8000].

Open your browser and visit http://127.0.0.1:8000. You should see the Laravel welcome page. Your server is running.


Step 8 — Essential VS Code Extensions

This is where your editor transforms from a basic text editor into a proper Laravel IDE.

Must-Have Extensions

Laravel Extension Pack — installs a curated bundle of Laravel-specific tools in one click:

Publisher: onecentlin
ID: onecentlin.laravel-extension-pack

Or install individually:

Extension Publisher Purpose
Laravel Blade Snippets Winnie Lin Blade syntax highlighting and snippets
Laravel Snippets Winnie Lin PHP/Laravel code snippets
Laravel Artisan Ryan Naddy Run artisan commands from VS Code command palette
Laravel Blade formatter Shuhei Hayashibara Auto-formats Blade files on save
PHP Intelephense Ben Massen PHP intellisense, go-to-definition, type inference
PHP DocBlocker Neil Brayfield Auto-generates PHPDoc blocks
DotENV mikestead Syntax highlighting for .env files
Prettier Prettier Formats JS, CSS, JSON files
GitLens GitKraken Enhanced Git history and blame

PHP Intelephense Setup

After installing Intelephense, disable VS Code's built-in PHP language features to avoid conflicts:

  1. Open Command Palette — Ctrl + Shift + P
  2. Search "Extensions: Show Built-in Extensions"
  3. Find PHP Language Features
  4. Click Disable

Keep PHP Language Basics enabled — it handles syntax coloring. Only disable PHP Language Features since Intelephense handles that better.


Step 9 — VS Code Workspace Settings

Create a .vscode/settings.json file inside your project root:

{
    "editor.formatOnSave": true,
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.tabSize": 4,
    "editor.insertSpaces": true,
    "[php]": {
        "editor.defaultFormatter": "bmewburn.vscode-intelephense-client",
        "editor.formatOnSave": true
    },
    "[blade]": {
        "editor.defaultFormatter": "shufo.vscode-blade-formatter",
        "editor.formatOnSave": true
    },
    "files.associations": {
        "*.blade.php": "blade"
    },
    "intelephense.environment.phpVersion": "8.2.0",
    "intelephense.files.exclude": [
        "**/vendor/**"
    ],
    "emmet.includeLanguages": {
        "blade": "html"
    }
}

This gives you auto-formatting on save for PHP, Blade, and JS files separately, correct file type associations, and Emmet support inside Blade templates.


Step 10 — Configure Xdebug (Optional but Recommended)

Debugging with dd() and var_dump() only gets you so far. Xdebug gives you real breakpoints inside VS Code.

Install Xdebug

For XAMPP on Windows, Xdebug is often already included. Check your php.ini:

php -m | grep xdebug

If not installed, download the correct .dll from xdebug.org/wizard — paste your phpinfo() output and it tells you exactly which file to download.

Configure php.ini

Add to the end of your php.ini (found at C:\xampp\php\php.ini):

[xdebug]
zend_extension=xdebug
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_port=9003
xdebug.client_host=127.0.0.1

VS Code Launch Configuration

Create .vscode/launch.json:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Listen for Xdebug",
            "type": "php",
            "request": "launch",
            "port": 9003,
            "pathMappings": {
                "${workspaceFolder}": "${workspaceFolder}"
            }
        }
    ]
}

Install the PHP Debug extension by Xdebug, press F5 to start listening, then set breakpoints by clicking the gutter next to any line number. When a request hits that code, VS Code pauses execution and lets you inspect every variable in scope.


Step 11 — Frontend Assets With Vite

Laravel 11 uses Vite for frontend asset bundling. Install Node dependencies first:

npm install

Run Vite in development mode (keep this running alongside php artisan serve):

npm run dev

For production builds:

npm run build

You'll typically have two terminals open during development — one running php artisan serve, one running npm run dev.


Daily Development Workflow

Once everything is set up, your typical workflow looks like this:

# Terminal 1 — PHP server
php artisan serve

# Terminal 2 — Vite assets
npm run dev

Common artisan commands you'll use constantly:

php artisan make:model Post -mcr
php artisan make:controller PostController
php artisan make:migration create_posts_table
php artisan migrate
php artisan migrate:rollback
php artisan route:list
php artisan cache:clear
php artisan config:clear
php artisan tinker

VS Code with the Laravel Artisan extension lets you run these from the command palette (Ctrl + Shift + P → "Artisan") without leaving the editor.


The Bottom Line

A proper Laravel setup in VS Code comes down to three layers — the right PHP version and Composer at the system level, a correctly configured .env and database at the project level, and the right extensions and workspace settings at the editor level. Get all three right once and your environment stays out of your way, letting you focus entirely on building.

PHP & Laravel — Zero to Hero Episode 07: Arrays — Storing and Managing Collections of Data

What Are We Doing in This Post?

So far every variable we created stored exactly one value. One name, one price, one score.

But real applications deal with collections. A list of products. A set of user details. A group of orders. Storing each one in a separate variable would be chaos.

Arrays solve this. An array is a single variable that holds multiple values. This is one of the most important data structures in PHP and you will use arrays in literally every project you ever build.


What is an Array?

Real world analogy: Think of an array like a train. A train has multiple compartments and each compartment holds passengers. The train itself has one name, but it carries many things inside it. A variable holds the train's name. An array is the train — one name, many compartments.

<?php

$colors = ["Red", "Green", "Blue", "Yellow"];

print_r($colors);

?>

Output:

Array ( [0] => Red [1] => Green [2] => Blue [3] => Yellow )

print_r is a built-in PHP function that displays the full contents of an array in a readable format. We use it constantly while working with arrays.

Notice the numbers 0, 1, 2, 3 next to each value. These are called indexes. PHP automatically assigns a numeric index to each item starting from 0, not 1. This is called zero-based indexing and it is standard across almost all programming languages.


Accessing Array Items

To access a specific item from an array, you use its index inside square brackets.

<?php

$colors = ["Red", "Green", "Blue", "Yellow"];

echo $colors[0]; echo "<br>"; echo $colors[2]; echo "<br>"; echo $colors[3];

?>

Output:

Red Blue Yellow

$colors[0] gives you the first item. $colors[2] gives you the third item. Remember — counting starts at zero.


Modifying and Adding Items

<?php

$colors = ["Red", "Green", "Blue"];

$colors[1] = "Purple";

$colors[] = "Orange";

print_r($colors);

?>

Output:

Array ( [0] => Red [1] => Purple [2] => Blue [3] => Orange )

Assigning to an existing index overwrites that value. Green became Purple at index 1.

Using empty square brackets $colors[] = adds a new item at the end of the array automatically. PHP figures out the next available index on its own.


Associative Arrays — Arrays With Named Keys

An indexed array uses numbers as keys. An associative array lets you define your own meaningful key names.

Real world analogy: An indexed array is like a numbered locker in a gym — locker 1, locker 2, locker 3. An associative array is like a hotel room with a name tag — "Presidential Suite", "Deluxe Room", "Standard Room." The name tells you exactly what is inside.

<?php

$user = [ "name" => "Gagan", "email" => "gagan@gmail.com", "age" => 22, "city" => "Delhi", "is_premium" => true ];

echo $user["name"]; echo "<br>"; echo $user["email"]; echo "<br>"; echo $user["age"];

?>

Output:

Gagan gagan@gmail.com 22

The => symbol maps a key to a value. To access a value you use its key name inside square brackets. This is far more readable than remembering that index 0 is name and index 3 is city.

Associative arrays are how you will represent a single record from a database in PHP. When Laravel fetches a user from the database, it comes back as an associative array or object with named fields exactly like this.


Multidimensional Arrays — Arrays Inside Arrays

A multidimensional array is an array where each item is itself an array. This lets you represent structured data like a table.

Real world analogy: Think of a spreadsheet. The spreadsheet is the outer array. Each row is an inner array. Each cell in a row is a value.

<?php

$students = [ ["name" => "Gagan", "score" => 88, "grade" => "B"], ["name" => "Rahul", "score" => 95, "grade" => "A"], ["name" => "Priya", "score" => 72, "grade" => "C"], ["name" => "Anjali", "score" => 60, "grade" => "C"], ];

foreach ($students as $student) { echo $student["name"] . " — Score: " . $student["score"] . " — Grade: " . $student["grade"]; echo "<br>"; }

?>

Output:

Gagan — Score: 88 — Grade: B Rahul — Score: 95 — Grade: A Priya — Score: 72 — Grade: C Anjali — Score: 60 — Grade: C

This structure is almost identical to what you get when you fetch multiple rows from a database. Each row is an associative array. All rows together form a multidimensional array. Learning to think in this structure now will make database work in Laravel feel completely natural.

To access a specific cell directly:

<?php

echo $students[1]["name"];

?>

Output: Rahul

$students[1] gets the second student (index 1). ["name"] gets the name field from that student's array.


Built-in Array Functions

PHP gives you a rich set of built-in functions for working with arrays. Here are the most important ones.

count — how many items are in the array:

<?php

$fruits = ["Apple", "Banana", "Mango", "Orange"]; echo count($fruits);

?>

Output: 4

Real world use: displaying "Showing 4 of 20 products" on a listing page.

array_push and array_pop — add and remove from the end:

<?php

$cart = ["Keyboard", "Mouse"];

array_push($cart, "Monitor"); print_r($cart); echo "<br>";

array_pop($cart); print_r($cart);

?>

Output:

Array ( [0] => Keyboard [1] => Mouse [2] => Monitor ) Array ( [0] => Keyboard [1] => Mouse )

array_push adds one or more items to the end. array_pop removes the last item. Real world use: managing a shopping cart — add items, remove the last added item.

array_shift and array_unshift — remove and add from the beginning:

<?php

$queue = ["Person A", "Person B", "Person C"];

array_shift($queue); print_r($queue); echo "<br>";

array_unshift($queue, "Person Z"); print_r($queue);

?>

Output:

Array ( [0] => Person B [1] => Person C ) Array ( [0] => Person Z [1] => Person B [2] => Person C )

array_shift removes the first item. array_unshift adds a new item to the beginning. Real world use: managing a queue system where the first person in line gets served first.

in_array — check if a value exists:

<?php

$allowed_roles = ["admin", "editor", "moderator"]; $user_role = "editor";

if (in_array($user_role, $allowed_roles)) { echo "Access granted."; } else { echo "Access denied."; }

?>

Output: Access granted.

Real world use: permission and role checking systems. Does this user have a role that allows them to access this page?

array_search — find the key of a value:

<?php

$cities = ["Mumbai", "Delhi", "Bangalore", "Chennai"]; $key = array_search("Bangalore", $cities); echo $key;

?>

Output: 2

Returns the index of the found value. Returns false if not found.

sort and rsort — sort indexed arrays:

<?php

$scores = [45, 92, 67, 23, 88];

sort($scores); print_r($scores); echo "<br>";

rsort($scores); print_r($scores);

?>

Output:

Array ( [0] => 23 [1] => 45 [2] => 67 [3] => 88 [4] => 92 ) Array ( [0] => 92 [1] => 88 [2] => 67 [3] => 45 [4] => 23 )

sort sorts ascending. rsort sorts descending.

ksort and asort — sort associative arrays:

<?php

$prices = ["Monitor" => 15000, "Keyboard" => 2500, "Mouse" => 800];

asort($prices); print_r($prices);

?>

Output:

Array ( [Mouse] => 800 [Keyboard] => 2500 [Monitor] => 15000 )

asort sorts by value while keeping key-value pairs intact. ksort sorts by key alphabetically.

array_merge — combine two arrays:

<?php

$electronics = ["Laptop", "Phone"]; $accessories = ["Case", "Charger", "Cable"];

$all_products = array_merge($electronics, $accessories); print_r($all_products);

?>

Output:

Array ( [0] => Laptop [1] => Phone [2] => Case [3] => Charger [4] => Cable )

array_unique — remove duplicate values:

<?php

$tags = ["php", "laravel", "php", "web", "laravel", "backend"]; $unique_tags = array_unique($tags); print_r($unique_tags);

?>

Output:

Array ( [0] => php [1] => laravel [3] => web [5] => backend )

Duplicates removed. Real world use: cleaning up tag lists or category selections where users may submit duplicates.

array_slice — extract a portion of an array:

<?php

$products = ["A", "B", "C", "D", "E", "F", "G"]; $page_one = array_slice($products, 0, 3); $page_two = array_slice($products, 3, 3);

print_r($page_one); echo "<br>"; print_r($page_two);

?>

Output:

Array ( [0] => A [1] => B [2] => C ) Array ( [0] => D [1] => E [2] => F )

Real world use: pagination. Show 3 items per page. Page one gets items 0 to 2. Page two gets items 3 to 5.


A Real World Example — Shopping Cart System

Let us build a simple shopping cart using everything from this episode.

Create cart.php in your phplearning folder:

<!DOCTYPE html> <html> <head> <title>Shopping Cart</title> </head> <body>

<?php

$cart = [ ["name" => "Wireless Mouse", "price" => 599, "qty" => 2], ["name" => "Mechanical Keyboard", "price" => 2499, "qty" => 1], ["name" => "USB Hub", "price" => 899, "qty" => 3], ];

$total = 0;

echo "<h2>Your Cart</h2>"; echo "<table border='1' cellpadding='8'>"; echo "<tr><th>Product</th><th>Price</th><th>Qty</th><th>Subtotal</th></tr>";

foreach ($cart as $item) { $subtotal = $item["price"] * $item["qty"]; $total += $subtotal;

echo "&lt;tr&gt;";
echo "&lt;td&gt;" . $item["name"] . "&lt;/td&gt;";
echo "&lt;td&gt;Rs. " . $item["price"] . "&lt;/td&gt;";
echo "&lt;td&gt;" . $item["qty"] . "&lt;/td&gt;";
echo "&lt;td&gt;Rs. " . $subtotal . "&lt;/td&gt;";
echo "&lt;/tr&gt;";

}

echo "</table>"; echo "<h3>Total Items: " . count($cart) . "</h3>"; echo "<h3>Grand Total: Rs. $total</h3>";

$discount = ($total > 3000) ? "10% discount applied!" : "No discount available."; echo "<p>$discount</p>";

?>

</body> </html>

Visit http://localhost:8080/phplearning/cart.php

You will see a proper cart table with product names, prices, quantities, subtotals, a grand total, and a discount message that appears automatically when the total crosses Rs. 3000.

This combines multidimensional arrays, foreach loops, arithmetic operators, the ternary operator, and string output — everything from the last four episodes working together as one complete feature.


What Did We Learn in This Post?

Arrays store multiple values in a single variable. Indexed arrays use numeric keys starting from 0. Associative arrays use custom named keys defined with =>.

Multidimensional arrays store arrays inside arrays — this mirrors how database rows look when fetched in PHP and Laravel.

Essential array functions: count, array_push, array_pop, array_shift, array_unshift, in_array, array_search, sort, rsort, asort, array_merge, array_unique, and array_slice.

Arrays, loops, and conditionals work together as the foundation of almost every dynamic feature in a real web application.


What is Coming in Episode 08?

Next we cover functions — how to write reusable blocks of code that you can call anywhere in your application.

Functions are how you stop repeating yourself. Instead of writing the same logic in ten different places, you write it once as a function and call it wherever you need it. Episode 08 covers defining functions, parameters, return values, default arguments, and variable scope.

See you in the next one.


Next Episode: Functions — Writing Reusable Code in PHP

This is Episode 07 of the PHP and Laravel — Zero to Hero series.

PHP & Laravel — Zero to Hero Episode 08: Functions — Writing Reusable Code in PHP

What Are We Doing in This Post?

So far every piece of code we wrote ran from top to bottom, once. If you needed the same logic in two places, you had to write it twice.

Functions fix this. A function is a named block of code that you define once and call as many times as you need, from anywhere in your file. This is one of the most important concepts in all of programming — it is how real applications stay clean, organized, and maintainable.


Defining and Calling a Function

Real world analogy: A function is like a vending machine. You set it up once. Every time someone presses a button, it performs the same action and gives an output. You do not rebuild the machine every time — you just press the button.

<?php

function greet() {
    echo "Hello! Welcome to my website.";
}

greet();
greet();
greet();

?>

Output:

Hello! Welcome to my website. Hello! Welcome to my website. Hello! Welcome to my website.

You define a function using the function keyword, then give it a name, then write the code inside curly braces. To run the function, you call it by writing its name followed by parentheses. The same block runs every time you call it.


Functions With Parameters — Sending Data In

A function becomes far more useful when you can pass data into it. The values you pass in are called arguments. The variables that receive them inside the function are called parameters.

<?php

function greet($name) {
    echo "Hello, $name! Welcome to my website.";
    echo "<br>";
}

greet("Gagan");
greet("Rahul");
greet("Priya");

?>

Output:

Hello, Gagan! Welcome to my website. Hello, Rahul! Welcome to my website. Hello, Priya! Welcome to my website.

The same function, three different outputs — because we passed three different names. The function does not care what name it receives. It just uses whatever comes in.

You can define multiple parameters separated by commas:

<?php

function introduce($name, $city, $job) {
    echo "$name is from $city and works as a $job.";
    echo "<br>";
}

introduce("Gagan", "Delhi", "Developer");
introduce("Rahul", "Mumbai", "Designer");

?>

Output:

Gagan is from Delhi and works as a Developer. Rahul is from Mumbai and works as a Designer.


Return Values — Getting Data Out

So far our functions just print things. But most of the time you want a function to calculate or process something and give you the result back so you can use it elsewhere. You do this with the return keyword.

<?php

function add($a, $b) {
    return $a + $b;
}

$result = add(10, 25);
echo $result;
echo "<br>";

echo add(100, 200);

?>

Output:

35 300

return sends the value back to wherever the function was called. Once return executes, the function stops — no code after return runs.

The returned value can be stored in a variable, echoed directly, or used inside another expression.

<?php

function calculate_total($price, $qty, $tax_rate) {
    $subtotal = $price * $qty;
    $tax = $subtotal * $tax_rate;
    return $subtotal + $tax;
}

$total = calculate_total(999, 3, 0.18);
echo "Total with tax: Rs. $total";

?>

Output:

Total with tax: Rs. 3536.46

Real world use: every e-commerce site has a function exactly like this — it takes a price, quantity, and tax rate and returns the final amount.


Default Parameter Values

Sometimes you want a parameter to have a fallback value in case the caller does not provide one.

<?php

function greet($name, $role = "User") {
    echo "Hello, $name! You are logged in as: $role";
    echo "<br>";
}

greet("Gagan", "Admin");
greet("Rahul");

?>

Output:

Hello, Gagan! You are logged in as: Admin Hello, Rahul! You are logged in as: User

When greet is called with two arguments, both are used. When called with one argument, $role falls back to its default value "User". Default parameters must always come after non-default ones.


Variable Scope — Where Variables Live

This is one of the most misunderstood topics for beginners so pay close attention.

In PHP, a variable defined outside a function is not automatically available inside that function. And a variable defined inside a function is not available outside it.

<?php

$message = "I am outside the function.";

function test() {
    echo $message;
}

test();

?>

Output: nothing — or a warning depending on your PHP settings.

PHP functions have their own separate scope. The variable $message exists in the global scope but the function cannot see it. To use a global variable inside a function, you must explicitly declare it with the global keyword.

<?php

$message = "I am outside the function.";

function test() {
    global $message;
    echo $message;
}

test();

?>

Output: I am outside the function.

However — in real professional PHP and especially in Laravel, using global variables inside functions is considered bad practice. The clean approach is to pass the value as a parameter instead.

<?php

$message = "I am outside the function.";

function test($msg) {
    echo $msg;
}

test($message);

?>

This is cleaner, more predictable, and easier to debug. Always prefer passing values as parameters over using global.


Returning Multiple Values Using an Array

A function can only return one value. But that value can be an array — which means you can effectively return multiple pieces of data.

<?php

function get_user() {
    return [
        "name" => "Gagan",
        "email" => "gagan@gmail.com",
        "role" => "Admin"
    ];
}

$user = get_user();
echo $user["name"];
echo "<br>";
echo $user["email"];
echo "<br>";
echo $user["role"];

?>

Output:

Gagan gagan@gmail.com Admin

This pattern is used constantly in Laravel — service functions and repository functions return arrays or objects with multiple fields.


A Real World Example — Invoice Generator

Let us put everything together. A clean invoice generator using multiple functions.

Create invoice.php in your phplearning folder:

<!DOCTYPE html>
<html>
<head>
    <title>Invoice</title>
</head>
<body>

<?php

function calculate_subtotal($price, $qty) {
    return $price * $qty;
}

function apply_discount($amount, $discount_percent) {
    return $amount - ($amount * $discount_percent / 100);
}

function apply_tax($amount, $tax_percent = 18) {
    return $amount + ($amount * $tax_percent / 100);
}

function format_price($amount) {
    return "Rs. " . number_format($amount, 2);
}

$items = [
    ["name" => "Laptop Stand", "price" => 1299, "qty" => 1],
    ["name" => "USB Hub", "price" => 899, "qty" => 2],
    ["name" => "Webcam", "price" => 2499, "qty" => 1],
];

$subtotal = 0;

echo "<h2>Invoice</h2>";
echo "<table border='1' cellpadding='8'>";
echo "<tr><th>Item</th><th>Price</th><th>Qty</th><th>Subtotal</th></tr>";

foreach ($items as $item) {
    $item_subtotal = calculate_subtotal($item["price"], $item["qty"]);
    $subtotal += $item_subtotal;

    echo "<tr>";
    echo "<td>" . $item["name"] . "</td>";
    echo "<td>" . format_price($item["price"]) . "</td>";
    echo "<td>" . $item["qty"] . "</td>";
    echo "<td>" . format_price($item_subtotal) . "</td>";
    echo "</tr>";
}

echo "</table>";

$after_discount = apply_discount($subtotal, 10);
$final_total = apply_tax($after_discount);

echo "<p>Subtotal: " . format_price($subtotal) . "</p>";
echo "<p>After 10% Discount: " . format_price($after_discount) . "</p>";
echo "<p>After 18% GST: " . format_price($final_total) . "</p>";

?>

</body>
</html>

Visit http://localhost:8080/phplearning/invoice.php

You will see a complete invoice with per-item subtotals, a discount applied to the total, GST added on top, and all prices formatted cleanly with two decimal places. Every calculation is in its own function — clean, reusable, and easy to change.


What Did We Learn in This Post?

Functions are named reusable blocks of code defined with the function keyword and called by name with parentheses.

Parameters let you pass data into a function. Multiple parameters are separated by commas.

return sends a value back from the function to the caller. Once return executes, the function stops.

Default parameter values provide fallbacks when an argument is not passed.

PHP functions have their own scope. Variables outside a function are not visible inside it unless passed as parameters or declared with global. Always prefer parameters.

A function can return an array to effectively send back multiple values at once.


What is Coming in Episode 09?

Next we cover forms and user input — how PHP receives data that a user types into a form on a webpage.

This is where PHP stops being theoretical and becomes genuinely interactive. A user fills out a form, clicks submit, and PHP processes whatever they typed. Episode 09 covers GET and POST methods, the $_GET and $_POST superglobals, basic input validation, and a complete working contact form.

See you in the next one.


Next Episode: Forms and User Input — Making PHP Interactive

This is Episode 08 of the PHP and Laravel — Zero to Hero series.

Template Engines in PHP — Bringing Structure to Your Frontend

If you've worked with frontend frameworks or other backend languages, you've probably encountered template engines — tools that let you write cleaner, more expressive view files without mixing raw language syntax into your markup. PHP developers have access to the same concept, and the ecosystem around it is mature and widely adopted.


First — Does PHP Even Need a Template Engine?

This is a fair question, because PHP itself is technically already a template language. You can embed PHP directly inside HTML:

<!DOCTYPE html>
<html>
<body>
    <h1>Hello, <?php echo htmlspecialchars($name); ?></h1>

    <?php if ($isLoggedIn): ?>
        <p>Welcome back!</p>
    <?php endif; ?>

    <?php foreach ($posts as $post): ?>
        <div><?php echo htmlspecialchars($post['title']); ?></div>
    <?php endforeach; ?>
</body>
</html>

This works. But look at it — it's noisy. The <?php ?> tags interrupt the HTML flow constantly, htmlspecialchars() has to be called manually every time you output a variable, and as files grow larger this becomes genuinely hard to read and maintain.

Template engines solve exactly this problem.


Yes — PHP Has Template Engines, and They Are Excellent

PHP's template engine ecosystem is one of the strongest in any backend language. Two engines dominate the space completely.


Twig — The Standalone Standard

Twig is developed and maintained by Symfony. It's the most widely used PHP template engine outside of Laravel and has a clean, expressive syntax inspired by Django's template language.

Installation

composer require twig/twig

Basic Setup

<?php

require_once 'vendor/autoload.php';

$loader = new \Twig\Loader\FilesystemLoader('templates');
$twig = new \Twig\Environment($loader, [
    'cache' => 'cache',
    'auto_reload' => true,
]);

echo $twig->render('home.html.twig', [
    'name' => 'Gagan',
    'posts' => $posts,
    'isLoggedIn' => true,
]);

Template File — templates/home.html.twig

<!DOCTYPE html>
<html>
<body>
    <h1>Hello, {{ name }}</h1>

    {% if isLoggedIn %}
        <p>Welcome back!</p>
    {% endif %}

    {% for post in posts %}
        <div>{{ post.title }}</div>
    {% endfor %}
</body>
</html>

Compare this to the raw PHP version above. Same output, dramatically cleaner syntax.

Template Inheritance in Twig

This is where Twig really shines — defining a base layout once and extending it across all pages:

{# templates/layout.html.twig #}

<!DOCTYPE html>
<html>
<head>
    <title>{% block title %}My App{% endblock %}</title>
</head>
<body>
    <nav>
        <a href="/">Home</a>
        <a href="/about">About</a>
    </nav>

    <main>
        {% block content %}{% endblock %}
    </main>

    <footer>
        <p>&copy; {{ "now"|date("Y") }}</p>
    </footer>
</body>
</html>
{# templates/home.html.twig #}

{% extends 'layout.html.twig' %}

{% block title %}Home — My App{% endblock %}

{% block content %}
    <h1>Hello, {{ name }}</h1>
    <p>Latest posts below.</p>
{% endblock %}

One layout file. Every page just fills in the blocks it needs. No copy-pasting HTML structure across files.

Key Twig Features

  • {{ variable }} — outputs a value, auto-escaped by default
  • {% if %}, {% for %}, {% block %} — logic and structure tags
  • {{ value|filter }} — built-in filters like upper, date, length, default
  • Auto-escaping — XSS protection out of the box, no manual htmlspecialchars() needed
  • Template inheritance and includes
  • Custom filters and functions you can register from PHP

Blade — Laravel's Built-In Engine

If you're using Laravel, you already have Blade — it's baked in with zero configuration. Blade has its own syntax and a few powerful features that go slightly beyond what Twig offers.

Basic Blade Template

<!DOCTYPE html>
<html>
<body>
    <h1>Hello, {{ $name }}</h1>

    @if($isLoggedIn)
        <p>Welcome back!</p>
    @endif

    @foreach($posts as $post)
        <div>{{ $post->title }}</div>
    @endforeach
</body>
</html>

Blade Layout System

{{-- resources/views/layouts/app.blade.php --}}

<!DOCTYPE html>
<html>
<head>
    <title>@yield('title', 'My App')</title>
</head>
<body>
    @include('partials.navbar')

    <main>
        @yield('content')
    </main>
</body>
</html>
{{-- resources/views/home.blade.php --}}

@extends('layouts.app')

@section('title', 'Home')

@section('content')
    <h1>Hello, {{ $name }}</h1>
    @include('partials.post-list', ['posts' => $posts])
@endsection

Blade-Specific Features Worth Knowing

{{-- Raw output, no escaping --}}
{!! $rawHtml !!}

{{-- Components --}}
<x-alert type="error" :message="$errorMessage" />

{{-- Stacks — push scripts/styles from child templates --}}
@push('scripts')
    <script src="/js/chart.js"></script>
@endpush

{{-- CSRF token for forms --}}
<form method="POST" action="/submit">
    @csrf
    <input type="text" name="title" />
    <button type="submit">Submit</button>
</form>

{{-- Authorization directives --}}
@can('edit-post', $post)
    <a href="/posts/{{ $post->id }}/edit">Edit</a>
@endcan

Blade also compiles down to plain PHP and gets cached, so there's no runtime performance penalty for using it.


Twig vs Blade — Quick Comparison

Feature Twig Blade
Framework Standalone / Symfony Laravel only
Syntax style {{ }} and {% %} {{ }} and @directives
Auto-escaping Yes, by default Yes, by default
Template inheritance Yes Yes
Components Via macros Native x-component system
Compilation/caching Yes Yes
Custom extensions Yes Yes
Use without framework Yes Possible but complex

Other Template Engines Worth Knowing

Beyond Twig and Blade, a few others exist in the PHP ecosystem:

  • Smarty — one of the oldest PHP template engines, still maintained, used in legacy codebases
  • Plates — a native PHP template engine with no new syntax, just plain PHP with structure added on top
  • Latte — developed by Nette framework, known for strong security features

For any new project today, Twig or Blade covers everything you'll need.


Auto-Escaping — The Most Underrated Benefit

Both Twig and Blade automatically escape output by default. This means:

{# User submitted: <script>alert('xss')</script> #}
{{ userInput }}

Twig renders this as safe text — the script tag is neutralized automatically. In raw PHP you have to remember htmlspecialchars() on every single echo. Template engines make XSS protection the default behavior, not something you have to manually remember.


The Bottom Line

PHP absolutely supports template engines, and the two main options — Twig and Blade — are production-grade, actively maintained, and used in some of the largest PHP applications in the world. They bring clean syntax, layout inheritance, component systems, and automatic security escaping to your frontend views.

If you're using Laravel, Blade is already there. If you're building something custom or framework-agnostic, Twig is the go-to choice. Either way, there's no reason to write raw PHP mixed into HTML once you've worked with a proper template engine.

PHP & Laravel — Zero to Hero Episode 06: Loops — Teaching PHP to Repeat Tasks Automatically

What Are We Doing in This Post?

In Episode 05, PHP learned how to make decisions. Now we teach it to repeat tasks.

Imagine you have 100 products to display on a page. You are not going to write echo 100 times. You write the logic once, tell PHP how many times to repeat it, and PHP handles the rest. That is what loops do.

Loops are one of the most powerful and most used concepts in all of programming. Master this episode and a huge chunk of real-world PHP will start making sense immediately.


The while Loop — Repeat As Long As Something is True

Real world analogy: You are filling a bucket with water. You keep pouring as long as the bucket is not full. The moment it is full, you stop. That is a while loop.

<?php

$count = 1;

while ($count <= 5) { echo "Count is: $count"; echo "<br>"; $count++; }

?>

Output:

Count is: 1 Count is: 2 Count is: 3 Count is: 4 Count is: 5

PHP checks the condition before every iteration. Is $count less than or equal to 5? If yes, run the block. After each run, $count increases by 1. When $count reaches 6, the condition becomes false and the loop stops.

The $count++ line is critical. Without it, $count never changes, the condition is always true, and the loop runs forever. This is called an infinite loop and it will crash your server. Always make sure your loop has a way to eventually become false.


The do while Loop — Run First, Check Later

The do while loop is similar to while, but with one key difference: it runs the code block first and checks the condition after. This guarantees the block runs at least once, even if the condition is false from the start.

<?php

$number = 10;

do { echo "Number is: $number"; echo "<br>"; $number++; } while ($number < 5);

?>

Output:

Number is: 10

Even though $number is already 10 and the condition $number < 5 is immediately false, the block still runs once because the check happens after the first execution.

Real world use: showing a user a form at least once, and then re-showing it only if validation fails.


The for Loop — When You Know Exactly How Many Times

The for loop is the most precise loop. You use it when you know in advance exactly how many times you want to repeat something.

<?php

for ($i = 1; $i <= 5; $i++) { echo "Iteration: $i"; echo "<br>"; }

?>

Output:

Iteration: 1 Iteration: 2 Iteration: 3 Iteration: 4 Iteration: 5

The for loop has three parts inside the parentheses, separated by semicolons.

The first part is the initializer: $i = 1. This runs once at the very beginning and sets up the counter variable.

The second part is the condition: $i <= 5. PHP checks this before every iteration. If true, the block runs. If false, the loop stops.

The third part is the increment: $i++. This runs after every iteration, updating the counter.

All three parts in one line makes for loops very readable. When you see a for loop, you immediately know the start, the end, and the step.


Counting Backwards and Custom Steps

The for loop is flexible. You can count in any direction and any step size.

<?php

for ($i = 10; $i >= 1; $i--) { echo "$i "; }

?>

Output: 10 9 8 7 6 5 4 3 2 1

<?php

for ($i = 0; $i <= 20; $i += 5) { echo "$i "; }

?>

Output: 0 5 10 15 20

The second example increments by 5 each time using $i += 5. You can step by any amount you need.


The foreach Loop — Made for Arrays

The foreach loop is designed specifically to loop through arrays. Arrays are lists of values — we will cover them in full detail in Episode 07. But for now, think of an array as a list.

<?php

$fruits = ["Apple", "Banana", "Mango", "Orange", "Grapes"];

foreach ($fruits as $fruit) { echo $fruit; echo "<br>"; }

?>

Output:

Apple Banana Mango Orange Grapes

foreach goes through the array one item at a time. On each iteration, the current item is stored in $fruit and you can use it inside the block. PHP automatically knows when the list ends and stops.

You do not manage a counter yourself. You do not worry about going out of bounds. foreach handles all of that. This is the loop you will use most often in real Laravel applications.


foreach With Key and Value

Arrays in PHP have both keys and values. foreach can give you both at the same time.

<?php

$person = [ "name" => "Gagan", "age" => 22, "city" => "Delhi", "job" => "Developer" ];

foreach ($person as $key => $value) { echo "$key: $value"; echo "<br>"; }

?>

Output:

name: Gagan age: 22 city: Delhi job: Developer

The => symbol maps a key to a value. This is called an associative array and we will go deep into arrays in Episode 07. For now just notice how foreach with $key => $value gives you both pieces of information on every iteration.


break and continue — Controlling Loop Flow

Sometimes you need to exit a loop early or skip a specific iteration. PHP gives you two keywords for this.

break — exit the loop immediately:

<?php

for ($i = 1; $i <= 10; $i++) { if ($i == 6) { break; } echo "$i "; }

?>

Output: 1 2 3 4 5

When $i reaches 6, break exits the loop completely. Numbers 6 through 10 are never printed.

Real world use: searching through a list for a specific item. Once you find it, you break out of the loop — no point checking the rest.

continue — skip this iteration and move to the next:

<?php

for ($i = 1; $i <= 10; $i++) { if ($i % 2 == 0) { continue; } echo "$i "; }

?>

Output: 1 3 5 7 9

When $i is even (divisible by 2 with no remainder), continue skips the echo and jumps straight to the next iteration. Only odd numbers get printed.

Real world use: processing a list but skipping items that do not meet certain criteria — for example, skipping inactive users when sending a newsletter.


Nested Loops — Loops Inside Loops

You can put a loop inside another loop. The inner loop completes fully for every single iteration of the outer loop.

<?php

for ($row = 1; $row <= 3; $row++) { for ($col = 1; $col <= 3; $col++) { echo "[$row,$col] "; } echo "<br>"; }

?>

Output:

[1,1] [1,2] [1,3] [2,1] [2,2] [2,3] [3,1] [3,2] [3,3]

For each value of $row, the inner loop runs completely through all three values of $col. Real world use: generating a calendar grid, building a multiplication table, or rendering rows and columns of data in a table.


A Real World Example — Product Listing Page

Let us build something practical. A simple product listing page that a real e-commerce site might generate.

Create a new file called products.php in your phplearning folder:

<!DOCTYPE html> <html> <head> <title>Product Listing</title> </head> <body>

<h2>Our Products</h2>

<?php

$products = [ ["name" => "Wireless Mouse", "price" => 599, "stock" => 15], ["name" => "Mechanical Keyboard", "price" => 2499, "stock" => 0], ["name" => "USB Hub", "price" => 899, "stock" => 8], ["name" => "Webcam HD", "price" => 1799, "stock" => 0], ["name" => "Monitor Stand", "price" => 1199, "stock" => 22], ];

foreach ($products as $product) { echo "<div style='border: 1px solid #ccc; padding: 10px; margin: 10px 0;'>"; echo "<h3>" . $product["name"] . "</h3>"; echo "<p>Price: Rs. " . $product["price"] . "</p>";

if ($product["stock"] &gt; 0) {
    echo "&lt;p style='color: green;'&gt;In Stock (" . $product["stock"] . " units)&lt;/p&gt;";
    echo "&lt;button&gt;Add to Cart&lt;/button&gt;";
} else {
    echo "&lt;p style='color: red;'&gt;Out of Stock&lt;/p&gt;";
}

echo "&lt;/div&gt;";

}

?>

</body> </html>

Visit http://localhost:8080/phplearning/products.php

You will see five product cards. Two of them show Out of Stock in red with no Add to Cart button. Three show In Stock in green with the button. This is exactly how real product listing pages work — one loop, one set of logic, handling every product dynamically.

Notice how loops and conditionals work together here. The foreach handles repetition. The if/else inside handles the per-product logic. These two concepts combined are the backbone of almost every dynamic web page you will ever build.


Choosing the Right Loop

Here is a simple guide for deciding which loop to use.

Use while when you do not know in advance how many times you need to loop — you just know the stopping condition.

Use do while when you need the block to run at least once before checking the condition.

Use for when you know the exact number of iterations upfront.

Use foreach when you are working with an array or a list of items. This will be your most used loop in Laravel.


What Did We Learn in This Post?

while loops repeat as long as a condition is true. Always ensure the condition can eventually become false.

do while loops run the block first and check the condition after — guaranteed at least one execution.

for loops are precise — initializer, condition, and increment all defined in one line. Best when you know the exact count.

foreach loops are built for arrays — they handle the iteration automatically without manual counter management.

break exits a loop immediately. continue skips the current iteration and moves to the next.

Nested loops let you work with grid-like data — a complete inner loop runs for every single outer iteration.


What is Coming in Episode 07?

We used arrays briefly in this episode. In Episode 07 we go deep into them.

Arrays are how PHP stores and manages lists and collections of data. Indexed arrays, associative arrays, multidimensional arrays, and all the built-in array functions PHP provides. This is one of the most important episodes in the entire Core PHP section.

See you in the next one.


Next Episode: Arrays — Storing and Managing Collections of Data in PHP

This is Episode 06 of the PHP and Laravel — Zero to Hero series.

Running PHP in the Terminal — No Browser Required

Most developers discover PHP through XAMPP, a local server, or a tutorial that immediately sets up Apache and a browser preview. So it's natural to assume PHP only lives inside a web server. But that's just one way to use it.

PHP has a fully functional Command Line Interface (CLI). You can write a .php file, run it from your terminal, and see output instantly — no browser, no server, no HTTP involved at all.


Do You Need to Install PHP Separately?

If you already have XAMPP installed, the answer is no.

XAMPP bundles PHP as part of its package. The PHP binary is already sitting on your machine — it's just not registered in your system's PATH by default, which is why your terminal doesn't recognize the php command out of the box.

You have two options:

  • Add XAMPP's PHP to your system PATH — recommended, one-time setup
  • Install PHP separately — only needed if you don't have XAMPP or want an independent installation

Option 1 — Use PHP From XAMPP (Windows)

Step 1 — Find Your XAMPP PHP Path

XAMPP installs PHP at:

C:\xampp\php

Confirm it by checking if php.exe exists there:

C:\xampp\php\php.exe

Step 2 — Add It to System PATH

  1. Press Win + S, search "Environment Variables"
  2. Click "Edit the system environment variables"
  3. Click "Environment Variables" button
  4. Under System variables, find and select Path, click Edit
  5. Click New and add:
C:\xampp\php
  1. Click OK on all dialogs

Step 3 — Restart Your Terminal

Close and reopen VS Code terminal or Command Prompt, then verify:

php --version

Expected output:

PHP 8.2.12 (cli) (built: Oct 24 2023)

That (cli) confirms you're running the CLI SAPI — not the web module. You're good to go.


Option 2 — Install PHP Separately (Without XAMPP)

If you want a clean, standalone PHP installation independent of XAMPP:

Windows

  1. Go to https://windows.php.net/download
  2. Download the latest VS16 x64 Non Thread Safe ZIP
  3. Extract it to a folder, for example:
C:\php
  1. Add C:\php to your system PATH using the same steps above
  2. Verify:
php --version

macOS

PHP comes pre-installed on older macOS versions, but for a current version use Homebrew:

brew install php

Then verify:

php --version

Linux (Ubuntu / Debian)

sudo apt update
sudo apt install php-cli

Verify:

php --version

Note — php-cli is a minimal package. It installs only what's needed to run PHP in the terminal, without Apache or any web server component.


Running Your First PHP Script in the Terminal

Create a file anywhere on your machine — call it index.php:

<?php

$name = "Gagan";
$age = 25;

echo "Name: " . $name . PHP_EOL;
echo "Age: " . $age . PHP_EOL;

Open your terminal in that folder and run:

php index.php

Output:

Name: Gagan
Age: 25

No browser. No server. Just PHP and your terminal.


The Interactive Shell

PHP also ships with an interactive shell — write and execute PHP expressions in real time without creating a file:

php -a
Interactive shell

php > $x = 10;
php > $y = 20;
php > echo $x + $y;
30
php > echo strtoupper("hello world");
HELLO WORLD
php >

Type exit to quit. Useful for quickly testing a function, checking a value, or experimenting with syntax.


Run a One-Liner Without Any File

For something quick, you don't even need a file:

php -r "echo date('Y-m-d') . PHP_EOL;"
2026-06-05

One Important Difference — HTML Tags Don't Work Here

Since there's no browser to render markup, HTML tags will print as plain text:

<?php
echo "<h1>Hello</h1>";

Terminal output:

<h1>Hello</h1>

For CLI scripts, use PHP_EOL for line breaks instead of <br>, and avoid HTML markup entirely. The terminal only cares about plain text.


What You Can Build With PHP CLI

Once you're comfortable running PHP in the terminal, a completely different category of work opens up:

  • Automation scripts — file processing, batch renaming, data cleanup
  • Cron jobs — scheduled tasks that run in the background on a server
  • Data migration — moving records between databases
  • Custom CLI tools — interactive prompts, argument parsing, system utilities
  • Running tests — PHPUnit, Pest, and all major PHP testing frameworks run entirely in the terminal

And if you use Laravel, you've already been using PHP CLI every time you typed php artisan — that entire command system is built on it.


The Bottom Line

PHP is not limited to the browser. The CLI has been part of PHP since version 4.3 and it works exactly the way you'd expect — write a file, run it, see output. If you have XAMPP, you already have everything you need, just add the path and you're set.

The browser-only workflow is a habit formed by how PHP is introduced to most developers. It was never a technical limitation.

Interesting Facts About PHP You Must Know

PHP powers a massive chunk of the internet and has been doing so for over three decades. Most developers use it daily without knowing its ba...