PHP Type Casting

PHP is a dynamically and weakly typed language, meaning a variable’s type is determined at runtime and PHP will happily convert values between types when it needs to. Type casting is the explicit, developer-controlled way of doing this conversion: you tell PHP “treat this value as this type” using a cast operator like (int) or (string), or with the settype() function. Understanding type casting is essential because PHP performs implicit conversions constantly (comparisons, string concatenation, arithmetic), and knowing the explicit rules helps you predict — and control — what those implicit conversions will do.

Overview: How Type Casting Works

Every PHP variable is stored internally as a zval (Zend value), a container that holds both a value and a type tag (integer, double, string, boolean, array, object, null, resource). Because the type lives with the value rather than with the variable name, the same variable can hold an integer at one moment and a string the next — this is what “dynamically typed” means. PHP also performs type juggling: it silently converts values when an operator or function expects a different type, such as when you use a string inside an arithmetic expression or an integer inside a string. Type casting is the explicit counterpart to this automatic juggling — instead of letting PHP guess, you use a cast operator to force a value into a specific type immediately, producing a brand-new value of that type without altering the original variable unless you reassign it.

PHP recognizes several cast operators, written as a target type in parentheses immediately before the value: (int)/(integer), (bool)/(boolean), (float)/(double)/(real), (string), (array), and (object). There used to be an (unset) cast that always produced null, but it was removed in PHP 8.0. Casting is a value-level operation: (int) $x evaluates to a new integer value; it does not change the declared type of $x itself, because plain PHP variables don’t have a “declared type” the way typed properties or function parameters do. If you want to convert a variable in place, PHP offers the settype() function, which mutates the variable directly and returns a boolean indicating success.

The conversion rules differ by target type. Converting to int or float from a numeric string parses the leading numeric portion of the string; if the value isn’t numeric at all, you get 0. Converting a float to an int always truncates toward zero — it never rounds. Converting to bool follows PHP’s “falsy” rules: 0, 0.0, "", "0", empty arrays, and null are all false; everything else, including the string "0.0" and negative numbers, is true. Converting to array wraps scalars in a single-element array, while converting an object to an array walks its properties. Converting an array to an object turns keys into public properties of a built-in stdClass instance.

Syntax

The general form of an explicit cast is:

$result = (type) $expression;

Where type is one of the recognized cast keywords. The table below summarizes each one:

Cast Aliases Resulting type
(int) (integer) Integer
(float) (double), (real) Floating-point number
(bool) (boolean) Boolean
(string) String
(array) Array
(object) Object (stdClass for scalars/arrays)

An alternative that mutates a variable in place instead of producing a new value is settype():

settype(<variable>, <type_name>);
  • variable — the variable to convert, passed by reference (it is modified directly).
  • type_name — a string such as "integer", "float", "string", "boolean", "array", "object", or "null".

The opposite function, gettype(), returns a variable’s current type as a string, which is useful for debugging casts.

Examples

Example 1: The Basic Cast Operators

<?php
$value = "42.9";

$asInt = (int) $value;
$asFloat = (float) $value;
$asBool = (bool) $value;
$asString = (string) 100;
$asArray = (array) "hello";

echo "Int: $asInt\n";
echo "Float: $asFloat\n";
echo "Bool: " . ($asBool ? 'true' : 'false') . "\n";
echo "String: $asString\n";
echo "Array: " . print_r($asArray, true);

Output:

Int: 42
Float: 42.9
Bool: true
String: 100
Array: Array
(
    [0] => hello
)

Casting the string "42.9" to int parses the leading numeric part and truncates the decimal, giving 42. Casting the same string to float keeps the full value. The non-empty string is truthy when cast to bool. Casting the scalar string "hello" to array wraps it as a single-element array with index 0.

Example 2: Normalizing Untrusted Input

<?php
function normalizeProductInput(array $input): array
{
    return [
        'id'      => (int) ($input['id'] ?? 0),
        'price'   => (float) ($input['price'] ?? 0),
        'inStock' => (bool) ($input['in_stock'] ?? false),
        'name'    => (string) ($input['name'] ?? ''),
    ];
}

$rawInput = [
    'id' => '15',
    'price' => '19.99',
    'in_stock' => '1',
    'name' => 'Wireless Mouse',
];

$product = normalizeProductInput($rawInput);

var_dump($product);

Output:

array(4) {
  ["id"]=>
  int(15)
  ["price"]=>
  float(19.99)
  ["inStock"]=>
  bool(true)
  ["name"]=>
  string(14) "Wireless Mouse"
}

This is a realistic use case: data arriving from a form, query string, or JSON payload is always a mix of strings. Casting each field to its intended type as it enters your application (here, inside a small normalizer function) keeps the rest of your code working with predictable, correctly-typed values instead of stray strings.

Example 3: Casting Between Objects and Arrays

<?php
class Point
{
    public function __construct(
        public float $x,
        public float $y,
    ) {}
}

$point = new Point(3.5, 7.2);
$asArray = (array) $point;

print_r($asArray);

$coords = ['x' => 1.0, 'y' => 2.0];
$asObject = (object) $coords;

echo $asObject->x . ", " . $asObject->y . "\n";

$value = "123";
settype($value, "integer");
var_dump($value);

Output:

Array
(
    [x] => 3.5
    [y] => 7.2
)
1, 2
int(123)

Because Point‘s properties are public, casting the object to an array produces clean keys matching the property names. Casting the associative array $coords to an object creates a stdClass with matching public properties. Finally, settype() converts $value from a string to an integer in place, rather than producing a separate value.

Under the Hood: What PHP Actually Does

When you write (int) $value, the Zend Engine dispatches to an internal conversion routine based on the current type of $value:

  • From a numeric string — PHP scans the string from the left for an optional sign, digits, and (for floats) a decimal point or exponent. It converts the numeric prefix and ignores everything after it. "42abc" becomes 42; a string with no leading digits, like "abc", becomes 0. Since PHP 8.0, leading and trailing whitespace is tolerated in “numeric strings”, but this parsing is stricter than many developers expect — always validate before trusting it.
  • From float to int — the fractional part is discarded (truncation toward zero), not rounded: (int) 9.9 is 9, and (int) -9.9 is -9. Floats that exceed the platform’s integer range produce undefined, platform-dependent results.
  • From array to object — PHP creates a stdClass instance and copies each array key/value pair into a public property of the same name.
  • From object to array — PHP copies each property into an array element keyed by the property name. Private properties get a key mangled with null bytes and the declaring class name, and protected properties get a key mangled with a null-byte prefix — this makes them awkward to access from the resulting array, and is a common source of confusion.
  • To bool — no parsing happens at all; PHP simply checks the value against its fixed list of “empty” values for that type.

Because casting always produces a brand-new zval rather than mutating the source, the original variable’s type is untouched — this is why (int) $x; as a standalone statement does nothing useful unless you capture or reassign the result, e.g. $x = (int) $x;.

Common Mistakes

Mistake 1: Assuming (int) Rounds Instead of Truncates

<?php
$price = 9.99;
$units = (int) $price;

echo "Whole units: $units";

Output:

Whole units: 9

The developer likely expected 10, but (int) always truncates toward zero — it never rounds. Round explicitly first if that’s the intent:

<?php
$price = 9.99;
$units = (int) round($price);

echo "Whole units: $units";

Output:

Whole units: 10

Mistake 2: Casting Unvalidated Input Hides Invalid Data

<?php
$input = "abc123";
$quantity = (int) $input;

echo "Quantity: $quantity";

Output:

Quantity: 0

Because "abc123" has no leading digits, the cast silently produces 0 — indistinguishable from a legitimately entered 0. This hides bad input instead of surfacing it. Validate before casting so invalid data is caught explicitly:

<?php
$input = "abc123";

if (!is_numeric($input)) {
    echo "Invalid quantity supplied";
} else {
    $quantity = (int) $input;
    echo "Quantity: $quantity";
}

Output:

Invalid quantity supplied

Best Practices

  • Never rely on a cast to validate data — (int) "hack" silently becomes 0 instead of raising an error. Validate untrusted input (form fields, query strings, API payloads) with is_numeric(), filter_var(), or a dedicated validation library before casting it.
  • Remember that (int) truncates, it doesn’t round. If you need rounding, call round() first and cast the result.
  • Prefer filter_var($value, FILTER_VALIDATE_INT) or FILTER_VALIDATE_FLOAT over a bare cast when the value might not be numeric at all — these return false on failure instead of silently defaulting to 0.
  • Use type declarations (parameter types, return types, and declare(strict_types=1);) to reduce how often you need casts in the first place — let PHP enforce types at the boundary instead of juggling them everywhere.
  • Be careful casting objects to arrays when the class has private or protected properties — the resulting keys are mangled with null bytes and are awkward to use. Prefer an explicit toArray() method on the class instead.
  • Use settype() only when you specifically need to mutate a variable in place; otherwise prefer the cast operator, which is clearer and doesn’t require passing by reference.
  • When converting to boolean, remember the specific falsy values (0, 0.0, "", "0", [], null) — the string "0.0" is truthy, which surprises many developers.

Practice Exercises

  1. Write a function toCents(float $dollars): int that converts a dollar amount like 19.99 into an integer number of cents (1999) without losing precision from float representation. Hint: casting straight to (int) after multiplying by 100 can be off by one — think about rounding first.
  2. Given an array of raw form values such as ['age' => '27', 'subscribed' => 'yes', 'rating' => '4.5'], write code that casts age to int, rating to float, and converts subscribed to a proper boolean, treating anything other than the literal string 'yes' as false. Note that a plain (bool) cast on the string 'no' won’t give you the answer you want — think about why.
  3. Write a small script that casts a stdClass object with three properties into an array using (array), then uses gettype() to print the type of the result. Predict the output before running it.

Summary

  • Type casting explicitly converts a value to a target type using operators like (int), (float), (bool), (string), (array), and (object), or via settype().
  • Casting produces a new value; it doesn’t retroactively change how the original variable was declared, since plain PHP variables aren’t statically typed.
  • Numeric string-to-number casts parse only the leading numeric portion and default to 0 for non-numeric input — never rely on this for validation.
  • Float-to-int casts truncate toward zero; they never round.
  • Object-to-array casts mangle private/protected property names; array-to-object casts create a stdClass with public properties.
  • Combine casting with explicit validation (is_numeric(), filter_var()) and modern type declarations for safer, more predictable code.