PHP Zero to Advanced #2: Variables, Data Types, Operators & Strings
In Part 1 we installed PHP and printed our first message. Now it is time to work with real data. Every program stores values, transforms them, and compares them. In this part you will learn how PHP variables work, which data types exist, how PHP converts between types, and the operators and string functions you will reach for constantly.
Variables and Constants
A variable in PHP always starts with a dollar sign $, followed by a name that begins with a letter or underscore. You do not declare a type up front: the type is determined by the value you assign. Variable names are case-sensitive, so $name and $Name are different variables.
<?php
$name = "Budi";
$age = 25;
$height = 1.72;
$isStudent = true;
echo "$name is $age years old.\n";
$age = $age + 1; // variables can be reassigned
echo "Next year: $age\n";
const APP_NAME = "Notes"; // constants cannot change
echo APP_NAME . "\n";
Output:
Budi is 25 years old.
Next year: 26
Notes
Use const (or define()) for values that never change, such as configuration names. Constants do not use the $ prefix and are written in UPPER_CASE by convention.
Data Types
PHP has four scalar types (int, float, string, bool), two compound types (array, object), and the special type null. Two functions are very handy while learning: get_debug_type() returns a readable type name, and var_dump() prints both the type and the value.
<?php
$values = [42, 3.14, "hello", true, null, [1, 2]];
foreach ($values as $value) {
echo get_debug_type($value) . "\n";
}
var_dump(42, 3.14, "hello", false, null);
Output:
int
float
string
bool
null
array
int(42)
float(3.14)
string(5) "hello"
bool(false)
NULL
Notice that var_dump shows the length of strings, e.g. string(5). Get used to reading this format, because you will use var_dump a lot when debugging.
Type juggling and casting
PHP is dynamically typed and converts values automatically when needed. This is called type juggling. You can also convert explicitly with casts such as (int), (float), (string), and (bool).
<?php
var_dump("10" + 5); // numeric string is converted
var_dump("3.5" * 2);
var_dump((int) "42abc"); // explicit cast takes leading digits
var_dump((bool) "0"); // "0" is falsy!
var_dump((bool) "false"); // non-empty string is truthy
var_dump(intdiv(7, 2), 7 % 2, 2 ** 10);
Output:
int(15)
float(7)
int(42)
bool(false)
bool(true)
int(3)
int(1)
int(1024)
The falsy values in PHP are: false, 0, 0.0, "", "0", [], and null. Everything else is truthy.
Operators
Arithmetic and assignment
<?php
$a = 10;
$b = 3;
echo $a + $b, "\n"; // 13
echo $a - $b, "\n"; // 7
echo $a * $b, "\n"; // 30
echo $a / $b, "\n"; // division returns float
echo $a % $b, "\n"; // modulo
echo $a ** $b, "\n"; // power
$count = 5;
$count += 2; // 7
$count *= 3; // 21
$count++; // 22
echo $count, "\n";
Output:
13
7
30
3.3333333333333
1
1000
22
Dividing two integers with / returns a float when the result is not whole. Use intdiv() if you need integer division.
Comparison and logical operators
The most important rule: prefer strict comparison === and !==. Loose comparison == converts types first, which can produce surprises.
<?php
var_dump(0 == "0"); // loose: compares values after conversion
var_dump(0 === "0"); // strict: type must match too
var_dump(1 <=> 2); // spaceship: -1, 0 or 1
var_dump(null ?? "default");
var_dump(true && false, true || false, !true);
$score = 75;
echo $score >= 70 ? "Pass" : "Fail", "\n";
Output:
bool(true)
bool(false)
int(-1)
string(7) "default"
bool(false)
bool(true)
bool(false)
Pass
The null coalescing operator ?? returns the left side if it exists and is not null, otherwise the right side. It is perfect for default values. The ternary ?: picks between two values based on a condition.
Working with Strings
Strings are everywhere in web development. You can join them with the . operator or interpolate variables inside double quotes. Curly braces make interpolation explicit and are required for array keys.
<?php
$first = "Siti";
$last = "Rahma";
$full = $first . " " . $last; // concatenation
echo $full . "\n";
echo "Full name: {$first} {$last}\n"; // curly braces for clarity
echo 'Single: {$first}' . "\n"; // no interpolation
$user = ['name' => 'Budi'];
echo "Hello, {$user['name']}!\n"; // array values need braces
Output:
Siti Rahma
Full name: Siti Rahma
Single: {$first}
Hello, Budi!
Essential string functions
<?php
$text = " Learning PHP is fun ";
echo strlen($text), "\n";
echo trim($text), "\n";
echo strtoupper(trim($text)), "\n";
echo str_replace("fun", "awesome", $text), "\n";
echo substr("Hello World", 0, 5), "\n";
echo ucwords("budi santoso"), "\n";
var_dump(str_contains("example.com", "example"));
var_dump(str_starts_with("php-8", "php"));
echo implode(", ", explode(" ", "red green blue")), "\n";
Output:
23
Learning PHP is fun
LEARNING PHP IS FUN
Learning PHP is awesome
Hello
Budi Santoso
bool(true)
bool(true)
red, green, blue
The functions str_contains(), str_starts_with(), and str_ends_with() were added in PHP 8 and are much more readable than the old strpos() !== false trick.
Multibyte strings
Functions like strlen count bytes, not characters. For text with accents, emoji, or non-Latin scripts, use the mb_* functions:
<?php
$word = "Café";
echo strlen($word), "\n"; // bytes
echo mb_strlen($word), "\n"; // characters
echo strtoupper($word), "\n";
echo mb_strtoupper($word), "\n";
Output:
5
4
CAFé
CAFÉ
Formatting numbers and text
<?php
$price = 1250000.5;
echo number_format($price), "\n";
echo number_format($price, 2, ',', '.'), "\n";
printf("%s bought %d items for %.2f\n", "Budi", 3, 45.5);
echo sprintf("%05d", 42), "\n";
echo str_pad("7", 3, "0", STR_PAD_LEFT), "\n";
Output:
1,250,001
1.250.000,50
Budi bought 3 items for 45.50
00042
007
number_format($n, 2, ',', '.') is a common way to format Indonesian Rupiah amounts, where the comma is the decimal separator and the dot is the thousands separator.
Heredoc and nowdoc
For multi-line text, heredoc behaves like a double-quoted string, while nowdoc (with the identifier in single quotes) behaves like a single-quoted string.
<?php
$name = "Siti";
$course = "PHP";
$message = <<<TEXT
Hello $name,
Welcome to the $course course.
TEXT;
echo $message, "\n";
$raw = <<<'TEXT'
Nowdoc keeps $name as-is.
TEXT;
echo $raw, "\n";
Output:
Hello Siti,
Welcome to the PHP course.
Nowdoc keeps $name as-is.
Common Mistakes
- Relying on loose comparison.
==has many edge cases. PHP 8 fixed some of them, but numeric strings still compare by value:
<?php
var_dump("abc" == 0); // PHP 8: false (PHP 7 said true!)
var_dump("1" == "01"); // true: both numeric strings
var_dump("10" == "1e1"); // true: same number
var_dump(100 == "1e2"); // true
var_dump("abc" === "abc");
Output:
bool(false)
bool(true)
bool(true)
bool(true)
bool(true)
- Using
+to join strings. In PHP,+is always numeric. Use.for strings. - Using
strlenon user names or Unicode text. Usemb_strlenwhen you care about characters. - Using floats for money. Floating point numbers are imprecise. Store amounts as integers (for example, in the smallest currency unit) or use a decimal library.
- Undefined variables. Reading a variable that was never assigned triggers a warning. Initialize your variables or use
??.
Exercise
Write a small receipt line: clean up a product name with extra spaces, capitalize it, calculate the total for a quantity, and format the price in Rupiah.
<?php
$product = " wireless mouse ";
$price = 149900;
$qty = 3;
$name = ucwords(trim($product));
$total = $price * $qty;
printf("%s x %d = Rp %s\n", $name, $qty, number_format($total, 0, ',', '.'));
echo "Name length: " . strlen($name) . "\n";
Output:
Wireless Mouse x 3 = Rp 449.700
Name length: 14
Try extending it: add a 11% tax line, and print the result with printf so that all numbers are aligned.
Summary
- Variables start with
$and take the type of their value; constants useconst. - Use
var_dump()andget_debug_type()to inspect values. - Prefer strict comparison
===; use??for defaults and<=>for ordering. - Join strings with
., interpolate with double quotes, and usemb_*functions for Unicode text. number_format,printf, andsprintfhandle formatting.
In Part 3 we will make decisions and repeat work with conditionals, loops, and the modern match expression.
Related articles
PostgreSQL Zero to Advanced #1: Introduction & Setup
Start the series by understanding what a relational database is, installing PostgreSQL locally, and getting comfortable with psql commands like \l, \c and \dt.
Ruby on Rails Zero to Advanced #1: Ruby Basics
Start the Rails journey with the language underneath it: irb, variables, strings, puts vs p, and symbols explained with runnable examples.
Python Zero to Advanced #1: Introduction & Setup
Start your Python journey: what Python is, how to install it, how to use the REPL, print your first output, and run .py files from the terminal.