With PHP 7 I just found out that if I have a function like this:
function automatic_int_conversion(int $value) {
echo gettype($value) . ' ' . $value;
}
and I call it with a float parameter like this one:
automatic_int_conversion(2.0); # prints out: integer 2
the float(2.0) value is automatically converted to an int, while if I call the function with the float(NAN) this way:
automatic_int_conversion(NAN); # TypeError
I get a type error although the documentation says:
As of PHP 7.0.0, instead of being undefined and platform-dependent, NaN and Infinity will always be zero when cast to integer.
IMHO this is pretty confusing and not consistent, because either every float is automatically converted or none.
Am I missing anything?
There is a difference between type casting (explicit) and type coercion (implicit). The parameter value is not being cast to an int, it is being coerced. You can cast any value to int, e.g.:
echo (int) "a"; // prints 0
But passing "a" to your type declared function throws an error, just as passing NAN does:
automatic_int_conversion("a"); // TypeError
Coercion only works the same as casting on a very limited set of values.
You might want to enable strict types to disable the coercions for function parameters, then it will work 'as expected':
declare(strict_types=1);
Related
This question already has an answer here:
PHP type hinting is being ignored, no TypeError exception is thrown
(1 answer)
Closed 1 year ago.
Type hints doesn't work in case of strings.
function def_arg(int $name, int $address, string $test){
return $name . $address . $test;
}
echo def_arg(3, 4, 10) ;
// It doesn't throws an error as expected.
On the other hand. if you give string in first argument, it throws an error saying it should be an int.
function def_arg(int $name, int $address, string $test){
return $name . $address . $test;
}
echo def_arg("any text", 4, "abc") ;
// this code throws an error
// "Fatal error: Uncaught TypeError: Argument 1 passed to def_arg() must be of the type integer, string given,"
why no error in case of strings ??
This is because by default, PHP will coerce values of the wrong type into the expected scalar type if possible. For example, a function that is given an integer for a parameter that expects a string will get a variable of type string.
see here
If you would use values that could be cast in your second example it would work:
function def_arg(int $name, int $address, string $test){
return $name . $address . $test;
}
echo def_arg("12", "22", 1) ;
This is because those values can be cast from string to int and vise versa.
It is possible to enable strict mode on a per-file basis. In strict mode, only a variable of exact type of the type declaration will be accepted, or a TypeError will be thrown. The only exception to this rule is that an integer may be given to a function expecting a float. Function calls from within internal functions will not be affected by the strict_types declaration.
I understand that, with a sting assigned to a variable, individual characters can be expressed by using the variable as an indexed array, but why does the code below, using an associative array, not just die with missing required? Why does 'isset' not throw FALSE on an array key that definitely doesn't exist?
unset($a);
$a = 'TESTSTRING';
if(!isset($a['anystring'])){
die('MISSING REQUIRED');
}else{
var_dump($a['anystring']);
}
The above example will output:
string(1) "T"
EDIT:
As indicated by Jelle Keiser, this is probably the safer thing to do:
if(!array_key_exists('required',$_POST)){
die('MISSING REQUIRED');
}else{
echo $_POST['required'];
}
What PHP is doing is using your string as a numeric index. In this case, 'anystring' is the equivalent of 0. You can test this by doing
<?php
echo (int)'anystring';
// 0
var_dump('anystring' == 0);
// bool(true)
PHP does a lot of type juggling, which can lead to "interesting" results.
$a is a string not an associative array.
If you want to access it that way you have to do something like this.
$a['anystring'] = 'TESTSTRING';
You need to use array_key_exists() to test if a key exists
The working of isset is correct in your case.
Because $a is a string, the index-operator will give you the specified char in the string at the declared position. (like a "Char-Array")
A small example:
$a = 'TESTSTRING';
echo $a[0]; // Output: T
echo $a[1]; // Output: E
// ...
This will output the first and the second character at index 0 and 1 of the string.
And because the index-operator always expects an integer value on strings. The given value will be automatically casted to an integer. You can see this, when you cast the string to an integer, like this:
echo (int) 'TESTSTRING'; // Output: 0
For char-access on strings, also see the PHP-Manual.
Try enabling PHP to show all errors by using error_reporting(E_ALL);
This should give you a warning saying you are using an illegal offset. PHP therefore automatically assumes you are looking for the first element in the array or letter in this case.
it works as expected for... it returned false... but when I force it to return true ... itz throws an error saying illegal offset somekind.... but still output the first string.... as anystring casted as int equals to 0.. check the version of php you are using bro... I used notepad++ to create the php file... no special ide...
I've seen some code written like this, and I'm really curious what it does and what it's for. Sorry for the unclear title, I appreciate all answers!
Edit: In particular I'm curious about the (string) $variable part
It's called type casting
Type casting in PHP works much as it does in C: the name of the desired type is written in parentheses before the variable which is to be cast.
<?php
$foo = 10; // $foo is an integer
$bar = (boolean) $foo; // $bar is a boolean
?>
The casts allowed are:
(int), (integer) - cast to integer
(bool), (boolean) - cast to boolean
(float), (double), (real) - cast to float
(string) - cast to string
(array) - cast to array
(object) - cast to object
(unset) - cast to NULL (PHP 5)
In your specific example a variable was being cast to a string before being passed as a parameter to testFunction()
It is a function call with an argument. In this case, a variable $variable has been cast to a string for the argument.
class wat
{
public $a = 3.14;
public $x = 9;
public $y = 2;
}
$a = new wat();
var_dump(1000 + $a);
var_dump($a + 1000);
The output is:
int(1001)
int(1001)
Well, adding the wat* object to an integer is obviously not the right thing to do, since PHP complains about it with "Object of class wat could not be converted to int", but still, what does it do?
(I also have a practical reason for asking this, I want to refactor a function to get rid of the "PHP Notice", while still keeping behaviour completely unchanged.)
*: http://img.youtube.com/vi/kXEgk1Hdze0/1.jpg
Addition (+) implicitly casts both operands to float if either one of them is float, otherwise both operands are cast to int (See paragraph #2.)
It seems that, at least for now, an object cast to int results in the value 1, hence the result 1000 + 1 = 1001 or 1 + 1000 = 1001, however, per the documentation, the behavior is undefined and should not be relied upon.
If you've turned on E_NOTICE error reporting, a notice should also be produced, saying that object could not be converted to int.
You're right that you shouldn't cast an Object to an Integer and you can't!
Than's why PHP assigns the integer 1 to the variable and should give you a notice which looks like this:
Notice: Object of class foo could not be converted to int in /path/to/file.php on line 1
$foo is now 1
int(1)
to be sure I get the code which actually do the cast:
from Zend/zend_operators.c:
case IS_OBJECT:
{
int retval = 1;
/* some other code */
ZVAL_LONG(op, retval); // < This sets the 1 you see.
return;
}
so it is not like i said before a internal cast ((int)(boolean)$object)
by doing this they preserve semantics of 0,"",NULL,false = false and !0,"...",Object = true
I tried looking up (int) but could only find documentation for the function int() in the PHP manual.
Could someone explain to me what the above code does, and exactly how it works?
You can find it in the manual in the section type juggling: type casting. (int) casts a value to int and is a language construct, which is the reason that it looks "funny".
It convert (tries at least) whatever the value of the variable is to a integer. If there are any letter etc, in front it will convert to a 0.
<?php
$var = '1a';
echo $var; // 1a
echo (int) $var; //1
$var2 = 'a2';
echo $var2; //a2
echo (int) $var2; // 0
?>
(int) converts a value to an integer.
<?php
$test = "1";
echo gettype((int)$test);
?>
$ php test.php
integer
Simple example will make you understand:
var_dump((int)8);
var_dump((int)"8");
var_dump((int)"6a6");
var_dump((int)"a6");
var_dump((int)8.9);
var_dump((int)"8.9");
var_dump((int)"6.4a6");
Result:
int(8)
int(8)
int(6)
int(0)
int(8)
int(8)
int(6)
In PHP, (int) will cast the value following it to an int.
Example:
php > var_dump((int) "5");
int(5)
I believe the syntax was borrowed from C.
What you are looking at there is known as type casting - for more information, see the manual page on type juggling.
The above piece of code casts (or converts) $_GET['page'] to an integer.
this kind of syntax (int) is called type casting. Basically it takes the variable following it and tries to force it into being an int
(int) is same as int()
see
http://php.net/manual/en/language.types.integer.php
it casts the variable following it to integer. more info from documentation:
http://php.net/manual/en/language.types.type-juggling.php
Type casting in PHP works much as it does in C: the name of the
desired type is written in parentheses before the variable which is to
be cast.
The casts allowed are:
(int), (integer) - cast to integer
(bool), (boolean) - cast to boolean
(float), (double), (real) - cast to float
(string) - cast to string
(array) - cast to array (object) - cast to object
(unset) - cast to NULL