Variables

A variable in PHP is a name that starts with a dollar sign, followed by a letter or underscore and then letters, digits or underscores. Assigning a value creates the variable; there is no let, var or type to write first.

<?php
$customerName = "J. de Groot";
$meterCount = 2;
$CustomerName = "someone else";   // a different variable: case matters

echo $customerName, " has ", $meterCount, " meters\n";

$copy = $meterCount;   // copies the value
$copy++;
echo "original $meterCount, copy $copy\n";
J. de Groot has 2 meters
original 2, copy 3

Assignment copies the value, so changing $copy leaves $meterCount alone. That holds for arrays too (PHP copies an array lazily, only when one of the two is changed). Objects are different: a variable holds a handle to the object, so two variables can point to the same one — see Classes and Objects. Inside double quotes, PHP replaces $name with the variable's value; single quotes do not (see Strings).

Undefined variables, isset() and unset()

Reading a variable that was never assigned does not stop the script. PHP 8 raises a warning and uses null:

Warning: Undefined variable $discount in /var/www/bill.php on line 3

The warning is a sign of a bug (often a typo in the name), so do not ignore it. When a value may legitimately be missing, test for it first: isset() is true when the variable exists and is not null, and the null coalescing operator ?? supplies a default without any warning. unset() removes a variable.

<?php
$tariff = 0.32;
var_dump(isset($tariff), isset($discount));

echo $discount ?? "no discount", "\n";

unset($tariff);
var_dump(isset($tariff));
bool(true)
bool(false)
no discount
bool(false)

Constants

A constant holds a value that cannot change. Constants have no $ and are written in capitals by convention: const VAT_RATE = 0.21; at the top level of a file, or define('VAT_RATE', 0.21);. PHP has many built-in ones, such as PHP_INT_MAX, PHP_EOL (the line ending) and PHP_VERSION.

The types

PHP has a small set of built-in types. A scalar type holds a single value; PHP has four of them: bool, int, float and string. The others hold several values, or none:

Type Example Holds
bool true, false A truth value
int 42, -7, 0x1F A whole number, 64-bit on current systems
float 3.5, 1.5e3 A floating-point number (double precision)
string "kWh", 'MTR-100231' A sequence of bytes, usually text
array [11.2, 9.8], ['kwh' => 9.8] An ordered map of keys to values
object new DateTimeImmutable() An instance of a class
null null "No value"; the only value of its type

Two more appear in older code and type declarations: callable (something that can be called as a function) and resource, a handle to something outside PHP, such as an open file. get_debug_type() (PHP 8+) returns the type name as you would write it in code; the older gettype() uses historical names such as "double" for floats:

<?php
$values = [42, 3.5, "kWh", true, null, [1, 2], new DateTimeImmutable('2026-10-02')];

foreach ($values as $value) {
    echo str_pad(get_debug_type($value), 19), gettype($value), "\n";
}
int                integer
float              double
string             string
bool               boolean
null               NULL
array              array
DateTimeImmutable  object

Integers and floats

An int is a 64-bit signed integer on every common platform today, so the largest is PHP_INT_MAX, 9223372036854775807. Unlike Python, PHP has no unlimited integers: a calculation that goes past the limit silently becomes a float and loses precision. Integers can be written in hexadecimal (0x1F), octal (0o17, PHP 8.1+; older code writes 017) and binary (0b1010), with underscores for readability (1_000_000).

<?php
var_dump(PHP_INT_MAX);
var_dump(PHP_INT_MAX + 1);        // overflow: becomes a float
var_dump(0x1F, 0o17, 0b1010, 1_000_000);

var_dump(0.1 + 0.2);
var_dump(0.1 + 0.2 == 0.3);
var_dump(round(0.1 + 0.2, 2) == 0.3);
int(9223372036854775807)
float(9.223372036854776E+18)
int(31)
int(15)
int(10)
int(1000000)
float(0.30000000000000004)
bool(false)
bool(true)

Floats have the same rounding errors as in every language that uses binary floating point. Never compare calculated floats with ==, and do not store money as a float: use whole cents in an int, or a decimal type in the database.

Booleans and truthiness

Wherever PHP needs a truth value — in an if, with !, && or || — it converts the value to bool. The values that count as false are false, 0, 0.0, the empty string "", the string "0", null and the empty array. Almost everything else is true, including some values that look empty:

<?php
$tests = [
    ['false', false], ['0', 0], ['0.0', 0.0], ['""', ""], ['"0"', "0"],
    ['null', null], ['[]', []],
    ['"0.0"', "0.0"], ['" "', " "], ['"false"', "false"], ['[0]', [0]],
];

foreach ($tests as [$label, $value]) {
    echo str_pad($label, 8), "is ", $value ? "true" : "false", "\n";
}
false   is false
0       is false
0.0     is false
""      is false
"0"     is false
null    is false
[]      is false
"0.0"   is true
" "     is true
"false" is true
[0]     is true

null

null means "no value". A variable is null when it has been assigned null, when it was never set (with a warning, see above) or after unset(); a function without a return value returns null. is_null($x) and $x === null test for it. Because PHP has only this one "empty" value, it plays the role of both undefined and null in JavaScript and of None in Python. In a database, PHP's null maps to SQL NULL.

Arrays and objects

A PHP array is one structure for both lists and key–value maps: [11.2, 9.8] has the keys 0 and 1, ['meter' => 'MTR-100231', 'kwh' => 1542.7] has string keys, and both keep their order. It is the workhorse of PHP and has its own page, Arrays. Objects are created from classes and are covered in Classes and Objects.

Inspecting values: var_dump() and friends

echo prints a value as text, which hides its type: false and null print as nothing, true as 1. When you need to know what a variable really contains — the first question in most debugging — use var_dump(): it prints the type and the value of each argument, including the length of strings and the full structure of arrays and objects.

<?php
$reading = ['meter' => 'MTR-100231', 'kwh' => 1542.7, 'estimated' => false, 'note' => null];

echo "echo false: [", false, "]  echo null: [", null, "]  echo true: [", true, "]\n";
print_r($reading);
var_dump($reading);
echo false: []  echo null: []  echo true: [1]
Array
(
    [meter] => MTR-100231
    [kwh] => 1542.7
    [estimated] =>
    [note] =>
)
array(4) {
  ["meter"]=>
  string(10) "MTR-100231"
  ["kwh"]=>
  float(1542.7)
  ["estimated"]=>
  bool(false)
  ["note"]=>
  NULL
}
Function Shows Use it for
echo / print The value as text Normal output
print_r() A readable structure, but false and null look empty A quick look at an array
var_dump() Type, length and value of everything Debugging: "what is really in here?"
var_export() Valid PHP code that recreates the value Generating configuration or test data

Type juggling

PHP is dynamically typed and, in places, weakly typed. Type juggling is PHP's name for the automatic conversion of a value to the type an operation needs: arithmetic needs numbers, the . operator needs strings, an if needs a boolean. The idea comes from the web, where every form field and URL parameter arrives as a string; PHP lets you calculate with "350" without converting it first.

<?php
var_dump("5" + "5");     // numeric strings become numbers
var_dump("5" . "5");     // . always makes a string
var_dump("1.5" + 1);
var_dump("1e3" + 0);     // exponent notation is numeric too
var_dump(" 42 " + 0);    // surrounding whitespace is allowed
var_dump(true + 1);      // true is 1, false is 0
var_dump(null + 5);      // null is 0
int(10)
string(2) "55"
float(2.5)
float(1000)
int(42)
int(2)
int(5)

Numeric strings

The conversion depends on what the string looks like. PHP 8 made the rules stricter (the "saner numeric strings" change):

How PHP 8 converts a string used in arithmetic. If the whole string is a number, optionally with surrounding whitespace, such as "42" or " 4.2e1 ", it is used as an int or float. If it only starts with a number, such as "3 apples", the leading number is used and PHP raises a warning. If it does not start with a number, such as "n/a", PHP throws a TypeError. String in arithmetic Is the whole string a number? yes int / float "42" " 4.2e1 " no Does it start with a number? yes leading number + Warning "3 apples" no TypeError "n/a" ""
PHP 8 rules for strings in arithmetic. Before PHP 8, "n/a" quietly became 0 with only a warning.

A string that only starts with a number still works, but PHP raises a warning, because the rest of the string was thrown away:

Warning: A non-numeric value encountered in /var/www/meter.php on line 4
int(4)

And a string that is not a number at all stops the script with a TypeError, which is better than calculating on with a silent zero:

<?php
$reading = "n/a";              // the meter could not be read
echo "Reading: $reading\n";
$cost = $reading * 0.32;
Reading: n/a
Fatal error: Uncaught TypeError: Unsupported operand types: string * float in example.php:4

Converting on purpose: type casts

A type cast converts a value to a given type explicitly, by writing the type in parentheses before it: (int), (float), (string), (bool) and (array). The functions intval(), floatval(), strval() and boolval() do the same. Casts between scalar types (string, int, float, bool) never fail and never warn — they always produce something:

<?php
var_dump((int) "12abc");    // takes the leading digits, silently
var_dump((int) "abc");      // no number at all: 0
var_dump((int) 12.9);       // cuts off the decimals, does not round
var_dump((int) -12.9);
var_dump((float) "1.5e3");
var_dump((bool) "0");
var_dump((bool) "false");   // a non-empty string
var_dump((string) 4.0);
var_dump(intval("0x1A", 16));
int(12)
int(0)
int(12)
int(-12)
float(1500)
bool(false)
bool(true)
string(1) "4"
int(26)

Because a cast always succeeds, it is the wrong tool to check input: (int) "12abc" happily gives 12. To find out whether a string is a valid number, validate it first. filter_var() returns the converted value, or false when the input does not fit; is_numeric() only answers yes or no:

<?php
foreach (["12", " 12 ", "12abc", "1e3"] as $input) {
    $asInt = filter_var($input, FILTER_VALIDATE_INT);
    echo str_pad(json_encode($input), 8),
        "int: ", var_export($asInt, true),
        ", numeric: ", var_export(is_numeric($input), true), "\n";
}
"12"    int: 12, numeric: true
" 12 "  int: 12, numeric: true
"12abc" int: false, numeric: false
"1e3"   int: false, numeric: true

Validating on the server is the first step of handling any input safely; see input validation and PHP and the Web.

strict_types

Functions can declare the types of their parameters and return value (function monthlyCost(int $kwh, float $tariff): float); Functions explains these type declarations. By default PHP juggles an argument to the declared type when it can, so the string "350" is accepted for an int:

<?php
function monthlyCost(int $kwh, float $tariff): float
{
    return $kwh * $tariff;
}

var_dump(monthlyCost("350", 0.32));   // "350" is converted to 350
var_dump(monthlyCost(350, 1));        // int 1 is accepted as a float
float(112)
float(350)

strict_types is a per-file switch, declare(strict_types=1);, that turns this off for function calls made from that file: an argument must then have exactly the declared type, or PHP throws a TypeError. The one exception is that an int is still accepted where a float is expected. The declare must be the very first statement in the file.

<?php
declare(strict_types=1);

function monthlyCost(int $kwh, float $tariff): float
{
    return $kwh * $tariff;
}

var_dump(monthlyCost(350, 1));        // still fine: int for float
var_dump(monthlyCost("350", 0.32));   // a string is not an int
float(350)
Fatal error: Uncaught TypeError: monthlyCost(): Argument #1 ($kwh) must be of type int, string given, called in example.php on line 10 and defined in example.php:4

Some details are easy to get wrong:

  • The mode belongs to the file that makes the call, not to the file where the function is defined. A library with strict_types=1 does not force strict calls on your code.
  • It applies to PHP's own functions too: in strict mode strlen(5) throws a TypeError instead of counting the characters of "5".
  • It only affects declared parameter and return types. Operators still juggle: "5" + "5" is 10 in strict mode as well.