Type Conversion and Type Coercion in PHP
A practical look at PHP type conversion and coercion: gettype, settype, var_dump, and why strict_types belongs in every file.
I have a long history with PHP’s type system. For years I treated PHP’s “thinking about types for you” as a convenience — then I learned it was also a trap, through hours lost debugging. This post approaches PHP type conversion and type coercion not as a feature list, but as a decision point.
PHP infers the type for you
When you declare a variable in PHP you don’t specify its type; PHP looks at the value and decides. You can see that decision with gettype():
$veri = "Muhammet Şafak";
echo gettype($veri); // string
gettype() returns one of: boolean, integer, double (including float), string, array, object, resource, NULL. In practice I rarely call it — but understanding how PHP sees a value is the foundation for every decision that follows.
Conversion: be explicit
There are a few ways to change a value’s type. settype() mutates the variable in place; cast operators ((int), (string), (bool)…) produce a new value; functions like intval() and strval() return the converted equivalent without touching the original.
$veri = "10";
$sayi = (int) $veri; // 10 — $veri is untouched
settype($veri, "integer"); // $veri is now an integer
All three work. My preference is cast operators: I want to see the intent while reading the code. Because settype() silently transforms a variable into something else, anyone reading the code later — usually me — can mistakenly assume the variable is still a string. Explicit conversion is explicit intent.
The real issue: type enforcement
PHP 7 introduced the ability to declare type hints for function parameters and return values. It’s one of the most valuable additions in the language’s history:
function topla(int $x, int $y): int
{
return $x + $y;
}
A type declaration is not just a constraint — it’s documentation. Anyone looking at a function signature sees exactly what it expects and what it returns, without guessing. When my own codebase grew to tens of thousands of lines, I felt the value of this concretely.
But there is a trap. By default PHP behaves “loosely”:
function topla(int $x, int $y): int { return $x + $y; }
echo topla("3", "4"); // 7 — strings were silently converted to int
"3" was a string; PHP accepted it as an int. It usually looks harmless — until something like "3 apples" silently becomes 3.
strict_types: non-negotiable
That’s why, for years, the first line of every PHP file I write is this:
declare(strict_types=1);
With that line, PHP no longer silently corrects a type mismatch — it throws a TypeError. You see the error the moment you call the function, not in production. The behaviour marketed as “flexibility” is really just debt that defers bugs to a later date — strict_types settles that debt.
The type is correct; the value still needs validation
A type hint says int; it does not say “int greater than zero”. My fastest tool for inspecting both a variable’s type and its value is still var_dump():
var_dump(3.14); // float(3.14)
The type system guarantees the type; it does not guarantee that the value satisfies a business rule. It’s important to keep type enforcement and value validation separate: one answers “is this a number?”, the other answers “is this number a valid age?”.
Summary
PHP’s loose type system is marketed as a convenience — but left unchecked, it is a source of ambiguity. My approach is clear: declare(strict_types=1) in every file, type declarations on every function, explicit casts for every conversion. The language gives you the freedom not to think about types — I prefer to hand that freedom back and make types visible again. In a long-lived codebase, the returns from this small discipline compound over time.
Comments
Sign in with your GitHub account to join the discussion. Comments are stored in GitHub Discussions.