45

PHP, as most of us know, has weak typing. For those who don't, PHP.net says:

PHP does not require (or support) explicit type definition in variable declaration; a variable's type is determined by the context in which the variable is used.

Love it or hate it, PHP re-casts variables on-the-fly. So, the following code is valid:

$var = "10";
$value = 10 + $var;
var_dump($value); // int(20)

PHP also allows you to explicitly cast a variable, like so:

$var = "10";
$value = 10 + $var;
$value = (string)$value;
var_dump($value); // string(2) "20"

That's all cool... but, for the life of me, I cannot conceive of a practical reason for doing this.

I don't have a problem with strong typing in languages that support it, like Java. That's fine, and I completely understand it. Also, I'm aware of - and fully understand the usefulness of - type hinting in function parameters.

The problem I have with type casting is explained by the above quote. If PHP can swap types at-will, it can do so even after you force cast a type; and it can do so on-the-fly when you need a certain type in an operation. That makes the following valid:

$var = "10";
$value = (int)$var;
$value = $value . ' TaDa!';
var_dump($value); // string(8) "10 TaDa!"

So what's the point?


Take this theoretical example of a world where user-defined type casting makes sense in PHP:

  1. You force cast variable $foo as int(int)$foo.
  2. You attempt to store a string value in the variable $foo.
  3. PHP throws an exception!! ← That would make sense. Suddenly the reason for user defined type casting exists!

The fact that PHP will switch things around as needed makes the point of user defined type casting vague. For example, the following two code samples are equivalent:

// example 1
$foo = 0;
$foo = (string)$foo;
$foo = '# of Reasons for the programmer to type cast $foo as a string: ' . $foo;

// example 2
$foo = 0;
$foo = (int)$foo;
$foo = '# of Reasons for the programmer to type cast $foo as a string: ' . $foo;

A year after originally asking this question, guess who found himself using typecasting in a practical environment? Yours Truly.

The requirement was to display money values on a website for a restaurant menu. The design of the site required that trailing zeros be trimmed, so that the display looked something like the following:

Menu Item 1 .............. $ 4
Menu Item 2 .............. $ 7.5
Menu Item 3 .............. $ 3

The best way I found to do that wast to cast the variable as a float:

$price = '7.50'; // a string from the database layer.
echo 'Menu Item 2 .............. $ ' . (float)$price;

PHP trims the float's trailing zeros, and then recasts the float as a string for concatenation.

10
  • This --> $value = $value . ' TaDa!'; Would cast $value back to string before doing assignment to final value of $value. Not really a surprise that if you force a type cast you get a type cast. Not sure what the point is in asking what the point of it is?
    – Chris
    Dec 7, 2010 at 16:20
  • "#3. PHP throws an exception!! <--- That would make sense." Actually that would make no sense at all. That's not even a problem in Java, JavaScript or any other C-syntax language that I know of. Who in their right mind would see that as desirable behavior? Do you want to have (string) casts everywhere?
    – Nicole
    Dec 7, 2010 at 17:36
  • @Renesis: you misunderstand me. What I meant was that an exception would be thrown only if a user has type-casted a variable. The normal behavior (where PHP does the casting for you) would of course not throw an exception. I'm trying to say that the user-defined type casting is moot, but if an exception were to be thrown it would suddenly make sense.
    – Stephen
    Dec 7, 2010 at 18:31
  • If you are saying $intval.'bar' throws an exception, I still disagree. That doesn't throw an exception in any language. (All languages I know of perform either an automatic cast or a .toString()). If you are saying $intval = $stringval throws an exception, then you are talking about a strongly typed language. I didn't mean to sound rude, so, sorry if I did. I just think it goes against what every developer is used to, and is much, much less convenient.
    – Nicole
    Dec 7, 2010 at 18:38
  • @Stephen - I posted an answer after some investigation. Really interesting results - I thought 2 of the cases would for sure show a purpose for casting, but PHP is even more strange than I thought.
    – Nicole
    Dec 7, 2010 at 21:05

7 Answers 7

32

In a weakly-typed language, type-casting exists to remove ambiguity in typed operations, when otherwise the compiler/interpreter would use order or other rules to make an assumption of which operation to use.

Normally I would say PHP follows this pattern, but of the cases I've checked, PHP has behaved counter-intuitively in each.

Here are those cases, using JavaScript as a comparison language.

String Concatentation

Obviously this is not a problem in PHP because there are separate string concatenation (.) and addition (+) operators.

JavaScript
var a = 5;
var b = "10"
var incorrect = a + b; // "510"
var correct = a + Number(b); // 15

String Comparison

Often in computer systems "5" is greater than "10" because it doesn't interpret it as a number. Not so in PHP, which, even if both are strings, realizes they are numbers and removes the need for a cast):

JavaScript
console.log("5" > "10" ? "true" : "false"); // true
PHP
echo "5" > "10" ? "true" : "false";  // false!

Function signature typing

PHP implements a bare-bones type-checking on function signatures, but unfortunately it's so flawed it's probably rarely usable.

I thought I might be doing something wrong, but a comment on the docs confirms that built-in types other than array cannot be used in PHP function signatures - though the error message is misleading.

PHP
function testprint(string $a) {
    echo $a;
}

$test = 5;
testprint((string)5); // "Catchable fatal error: Argument 1 passed to testprint()
                      //  must be an instance of string, string given" WTF?

And unlike any other language I know, even if you use a type it understands, null can no longer be passed to that argument (must be an instance of array, null given). How stupid.

Boolean interpretation

[Edit]: This one is new. I thought of another case, and again the logic is reversed from JavaScript.

JavaScript
console.log("0" ? "true" : "false"); // True, as expected. Non-empty string.
PHP
echo "0" ? "true" : "false"; // False! This one probably causes a lot of bugs.

So in conclusion, the only useful case I can think of is... (drumroll)

Type truncation

In other words, when you have a value of one type (say string) and you want to interpret it as another type (int) and you want to force it to become one of the valid set of values in that type:

$val = "test";
$val2 = "10";
$intval = (int)$val; // 0
$intval2 = (int)$val2; // 10
$boolval = (bool)$intval // false
$boolval2 = (bool)$intval2 // true
$props = (array)$myobject // associative array of $myobject's properties

I can't see what upcasting (to a type that encompasses more values) would really ever gain you.

So while I disagree with your proposed use of typing (you essentially are proposing static typing, but with the ambiguity that only if it was force-cast into a type would it throw an error — which would cause confusion), I think it's a good question, because apparently casting has very little purpose in PHP.

8
  • Okay, how about an E_NOTICE then? :)
    – Stephen
    Dec 7, 2010 at 21:10
  • @Stephen E_NOTICE might be ok, but to me the ambiguous state is concerning - how would you know by looking at one bit of code if the variable was in that state (having been cast somewhere else)? Also, I found another condition and added it to my answer.
    – Nicole
    Dec 8, 2010 at 7:06
  • 1
    As for Boolean evaluation, PHP docs clearly state what is considered to be false when evaluating to boolean and both empty string and a string "0" are considered false. So even when this feels bizare, it is normal and expected behaviour. Jan 5, 2011 at 22:48
  • to add bit to confusion: echo "010" == 010 and echo "0x10" == 0x10 ;-)
    – vartec
    Mar 25, 2013 at 15:00
  • 1
    Note that as of PHP 7, this answer's notes on scalar type hinting are inaccurate.
    – John V.
    Jun 4, 2017 at 8:35
15

You're mixing the weak/strong and dynamic/static type concepts.

PHP is weak and dynamic, but your problem is with the dynamic type concept. That means, variables don't have a type, values do.

A 'type casting' is an expression that produces a new value of a different type of the original; it doesn't do anything to the variable (if one is involved).

The one situation where I regularly type cast values is on numeric SQL parameters. You're supposed to sanitize/escape any input value you insert into SQL statements, or (much better) use parameterized queries. But, if you want some value that MUST be an integer, it's much easier to just cast it.

Consider:

function get_by_id ($id) {
   $id = (int)$id;
   $q = "SELECT * FROM table WHERE id=$id LIMIT 1";
   ........
}

if I left out the first line, $id would be an easy vector for SQL injection. The cast makes sure that it's a harmless integer; any attempt to insert some SQL would simply result in a query for id=0

7
  • I'll accept that. Now, as far as the usefulness of Type Casting?
    – Stephen
    Dec 7, 2010 at 15:40
  • It's funny that you bring up SQL injection. I was arguing over on SO with someone using this technique to sanitize user input. But what problem does this method solve that mysql_real_escape_string($id); doesn't already?
    – Stephen
    Dec 7, 2010 at 20:08
  • it's shorter :-) of course, for strings i use parameterized queries, or (if using the old mysql extension) escape it.
    – Javier
    Dec 7, 2010 at 20:11
  • 2
    mysql_real_escape_string() has a vulnerability of doing nothing to strings like '0x01ABCDEF' (i.e. hexadecimal representation of an integer). In some multibyte encodings (not Unicode lucklily) a string like this can be used to break the query (because it gets evaluated by MySQL to something that contains a quote). That's why neither mysql_real_escape_string() nor is_int() is the best choice for dealing with integer values. Typecasting is.
    – Mchl
    Jan 3, 2011 at 12:30
  • A link with some more details: ilia.ws/archives/…
    – Mchl
    Jan 3, 2011 at 12:45
4

One use for type casting in PHP that I've found:

I'm developing an android app which makes http requests to PHP scripts on a server to retrieve data from a database. The script stores data in the form of a PHP object (or associative array) and is return as a JSON object to the app. Without type casting I would receive something like this:

{ "user" : { "id" : "1", "name" : "Bob" } }

But, using PHP type casting (int) on the user's id when storing it the PHP object, I get this returned to the app instead:

{ "user" : { "id" : 1, "name" : "Bob" } }

Then when the JSON object is parsed in the app, it saves me from having to parse the id to an Integer!

See, very useful.

2
  • I hadn't considered formatting data for external, strong-typed systems to consume. +1
    – Stephen
    Jan 15, 2016 at 16:55
  • This is especially true when talking JSON to external systems like Elasticsearch. A json_encode()-ed value "5" will give very different results than the value 5. Jun 27, 2018 at 7:55
3

One example is objects with a __toString method: $str = $obj->__toString(); vs $str = (string) $obj;. There is much less typing in the second, and the extra stuff is punctuation, which takes longer to type. I also think it's more readable, although others may disagree.

Another is making a single-element array: array($item); vs (array) $item;. This will put any scalar type (integer, resource, etc.) inside an array.
Altenatively, if $item is an object, its properties will become keys to their values. However, I do think that object->array conversion is a bit strange: private and protected properties are part of the array, and renamed. To quote the PHP documentation: private variables have the class name prepended to the variable name; protected variables have a '*' prepended to the variable name.

Another use is converting GET/POST data into appropriate types for a database. MySQL can handle this itself but I think the more ANSI-compliant servers might reject the data. The reason I only mention databases is that in most other cases, the data will have an operation performed on it according to its type at some point (i.e. int/floats will usually have calculations performed on them, etc.).

3
  • These are great examples of how type casting works. Yet, I'm not convinced that they fill a need. Yes, you can convert an object to an array, but why? I guess because you could then use the myriad PHP array functions on the new array, but I cannot fathom how that would be useful. Also, PHP usually creates string queries to send to a MySQL database, so the variable type is irrelevant (automatic string conversion from int or float will occur when building the query). (array) $item is neat, but useful?
    – Stephen
    Dec 7, 2010 at 15:30
  • I actually agree. As I was typing them up, I thought that I would think of some uses, but I didn't. For the database stuff, if the parameters are part of the query string, then you're right, casting has no purpose. However, when using parametrised queries (which is always a good idea), it is possible to specify the parameters' types. Dec 7, 2010 at 16:26
  • Aha! You may have hit a valid reason with Parameterized Queries.
    – Stephen
    Dec 7, 2010 at 17:15
0

This script:

$tags = _GET['tags'];
foreach ($tags as $tag) {
    echo 'tag: ', $tag;
}

will run fine for script.php?tags[]=one but will fail for script.php?tags=one, because _GET['tags'] returns an array in the first case but not in the second. Since the script is written to expect an array (and you have less control over the query string sent to the script), the problem can be solved by appropriately casting the result from _GET:

$tags = (array) _GET['tags'];
foreach ($tags as $tag) {
    echo 'tag: ', $tag;
}
-1

It can also be used as a quick and dirty method to ensure untrusted data isn't going to break something eg if using a remote service which has crap validation and must only accept numbers.

$amount = (float) $_POST['amount'];

if( $amount > 0 ){
    $remoteService->doacalculationwithanumber( $amount );    
}

Obviously this is flawed and also handled implicitly by the comparison operator in the if statement, but is helpful in ensuring you know exactly what your code is doing.

2
  • 1
    Except that it doesn't break. Even if $_POST['amount'] contained a garbage string, php would evaluate that it was not greater than zero. If it contained a string that represented a positive number, it would evaluate true.
    – Stephen
    Jan 15, 2016 at 19:11
  • 1
    Not entirely true. Consider $amount is being passed to a third party service inside the conditional which must receive a number. If someone were to pass in $_POST['amount']="100 bobbins", removing (float) would still allow the conditional to pass but $amount would not be a number.
    – Gruffputs
    Feb 4, 2016 at 16:26
-2

One "use" of PHP re-casting variables on-the-fly that I see in use often is when retrieving data from external sources (user input or database). It lets coders (note that I did not say developers) ignore (or not even learn) the different datatypes available from different sources.

One coder (note that I did not say developer) whose code I have inherited and still maintain does not seem to know that there exists a difference between the string "20" that is returned in the $_GET super variable, to between the integer operation 20 + 20 when she adds it to the value in the database. She is only lucky that PHP uses . for string concatenation and not + like every other language, because I have seen her code "add" two strings (a varcahr from MySQL and a value from $_GET) and get an int.

Is this a practical example? Only in the sense that it lets coders get away with not knowing what datatypes they are working with. I personally hate it.

2
  • 2
    I don't see how this answer adds value to the discussion. The fact that PHP allows an engineer (or programmer, or coder, what have you) to perform math operations on strings is already abundantly clear in the question.
    – Stephen
    Jan 15, 2016 at 16:52
  • Thank you Stephen. I perhaps used too many words to say "PHP lets people who do not know what a datatype is create applications that do what they expect under ideal conditions".
    – dotancohen
    Jan 15, 2016 at 18:32

Not the answer you're looking for? Browse other questions tagged or ask your own question.