Variables, Types and Type Juggling
How PHP stores values: variables with $, the scalar types, null, arrays and objects, type juggling between strings and numbers, var_dump, and strict_types.
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):
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=1does not force strict calls on your code. -
It applies to PHP's own functions too: in strict mode
strlen(5)throws aTypeErrorinstead of counting the characters of"5". -
It only affects declared parameter and return types. Operators
still juggle:
"5" + "5"is10in strict mode as well.