I have a collegue who constantly assigns variable and forces their type. For example he would declare something like so:
$this->id = (int)$this->getId();
or when returning he will always return values as such:
return (int)$id;
I understand that php is a loosely typed language and so i am not asking what the casting is doing. I am really wondering what the benefits are of doing this - if any - or if he is just wasting time and effort in doing this?
There are a few benefits.
Type-checking. Without type-checking, 0 == false and 1 == true.
Sanitizing. If you're inserting the value into an SQL query, you can't have SQL injection because string values are converted to zero.
Integrity. It prevents inserting invalid database data. Again, it converts to zero, so you won't be trying to insert a string into a integer field in a database.
To explicitly convert a value to
integer, use either the (int) or
(integer) casts. However, in most
cases the cast is not needed, since a
value will be automatically converted
if an operator, function or control
structure requires an integer
argument. A value can also be
converted to integer with the intval()
function.
http://www.php.net/manual/en/language.types.integer.php#language.types.integer.casting
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. That is to say, if a
string value is assigned to variable
$var, $var becomes a string. If an
integer value is then assigned to
$var, it becomes an integer.
An example of PHP's automatic type
conversion is the addition operator
'+'. If either operand is a float,
then both operands are evaluated as
floats, and the result will be a
float. Otherwise, the operands will be
interpreted as integers, and the
result will also be an integer. Note
that this does not change the types of
the operands themselves; the only
change is in how the operands are
evaluated and what the type of the
expression itself is.
http://www.php.net/manual/en/language.types.type-juggling.php
You can do something like this instead.
function hello($foo, $bar) {
assert(is_int($foo));
assert(is_int($bar));
}
http://php.net/manual/en/function.assert.php
Related
So the syntax for if statements is:
if(condition){
//code to execute
}
Then why do functions when placed in place of conditions work in PHP.
In PHP (and many languages) there is no specific concept of a "condition"; the actual definition of an if statement is:
if(expression){
//code to execute
}
An "expression" is simply anything that can be evaluated and results in a value. A single value, like 42 is an expression on its own, as is a simple sum like 1 + 1. A function call like strlen('hello') is also an expression, evaluating to the result of the function; the function has to be run, which may have side effects, to determine that result. Expressions can be arbitrarily complex by linking then with operators, like strlen('hello') * 2 + 1.
Commonly in an if statement, you'd have something like $foo === $bar - this is just an expression that uses the === operator to give a boolean result, either true or false. PHP will evaluate that expression, and then decide whether to run the conditional code based on the result. The expression can be as simple or complex as you want - if(true) is valid, though not often useful, and so is if((strlen('hello') * 2 + 1) > 10).
If the result of the expression is not a boolean, PHP "coerces" it into one, as described on the manual page about the boolean type. For instance strlen($foo) evaluates to an integer, and all integers other than zero coerce to true, so if(strlen($foo)) acts like if(strlen($foo) !== 0).
As well as function calls, there are other expressions which have side effects. For instance, an assignment can also be used as an expression, evaluating to the value assigned. This lets you do things like $foo = $bar = 0; where $foo is assigned the result of running $bar = 0; which is of course 0. It also lets you put assignments inside if statements, like if ( $result = getData() ) { ... }, which is shorthand for $result = getData(); if ( $result ) { ... } This technique should be used with care, though, because at a glance it can be hard to spot the difference between = (assignment) and == (weak comparison).
The values returned in a PHP if condition are not restricted to be "strictly" Boolean, however the condition is expected to be Boolean. Why? Because all PHP variables types (inbuilt or user-defined) can be implicitly type-casted (converted automatically) to Boolean. According to the PHP manual:
To explicitly convert a value to bool, use the (bool) or (boolean) casts. However, in most cases the cast is unnecessary, since a value will be automatically converted if an operator, function or control structure requires a bool argument.
The PHP manual also explicitly specifies the falsy values for the different variable types including user defined types with all other values not specified being truthy:
the following values are considered false:
the boolean false itself
the integer 0 (zero)
the floats 0.0 and -0.0 (zero)
the empty string, and the string "0"
an array with zero elements
the special type NULL (including unset variables)
SimpleXML objects created from attributeless empty elements, i.e. elements which have neither children nor attributes.
Every other value is considered true (including any resource and NAN).
Therefore, to explicitly answer your question:
why do functions when placed in place of conditions work in PHP?
One reason I know of, is so you can conveniently perform assignments in the conditions:
function inverse_power($base, $exp)
{
if($power = pow($base, $exp)) {
return 1/$power;
}
else {
return "logical error: you can't divide by zero";
}
}
echo inverse_power(2,1); // 0.5
echo inverse_power(0,1); // logical error: you can't divide by zero
From the above example, you see the feature saves me multiple lines of code. Note that $power is not explicitly Boolean, but will be automatically converted to Boolean only to test the condition. The actual value of $power still persists throughout the function.
Because a condition is a boolean and functions can return booleans. And for conditions to work, the condition itself has to be evaluated, so it can be a function that is executed also.
I'm a little unclear about the rule for integer and string variables in php.
If I am dealing with counters (simple integers starting with 1 and counting upwards), do I need to specify variables as integers and then convert to strings when I use or can I leave them as strings and conversions will happen automatically in php at run time?
Or are there too many specific cases that have different rules? Some thoughts would be appreciated...
PHP automatically converts valriables when needed. you just have to be careful when you are going to compare them.
If you compare a number with a string or the comparison involves numerical strings, then each string is converted to a number and the comparison performed numerically. These rules also apply to the switch statement. The type conversion does not take place when the comparison is === or !== as this involves comparing the type as well as the value.
take a look at this
There's no variable declaration in PHP the variable will take the type appropiate to the data you assign to it.
$var = 1; //here $var is an int
$var = '1'; // now is a string
$var = true; //and now a boolean
So there's this page on the php site which shows the result of comparing different values:
http://php.net/manual/en/types.comparisons.php
This is a helpful reference, but I would rather not have to visit this page every time I want to make sure that I'm doing type comparison right. So my question is
Is there some kind of underlying philosophy/reasoning behind the logic of type comparisons on PHP?
For example, I can see that for loose comparisons:
1, -1, "1" and "-1" can be treated as TRUE and 0 and "0" can be treated as FALSE;
Comparing the string value of a number against the number itself with yield TRUE;
but it becomes a bit hairy from then on trying to establish a pattern.
For casting directly to a boolean this is how it works.
All string with a length > 0 are true
All non 0 numbers are true
All non-empty arrays are true
All objects are true
Then these rules for comparing variables of the same type:
Objects are equivalent if their properties are equal
Arrays are equivalent if their keys and elements are equal
Strings are equivalent if they would produce the same output
Numbers are equivalent if they are mathematically equivalent
Booleans are equivalent if they have the same value.
For variable of different types the type that is higher on the above list is cast to the one that is lower then the comparison is made.
=== and !== operators don't cast prior to comparing but you should note objects are only === if they are the same instance.
The really odd one is arrays, they are === if they have the same keys and values defined in the same order.
$a = array("a"=>1, "b"=>2);
$b = array("b"=>2, "a"=>1);
$a == $b; // true
$a === $b; // false
and empty() is equivalent to !(bool)$var
EXCEPTIONS
Casting an array to a string will trigger a notice and unhelpfully cast as the text Array
Casting an object without a __toString method to a string will get you a fatal error.
Objects will not implicitly cast to an array, so any time you compare an object to an array it will yield a false (UPDATE confirmed that this is true even if object implemtents the ArrayAccess interface)
For strict === comparision, the logic is easy: each value entity is equal only to itself, so TRUE === TRUE, "1" === "1", but "1" !== 1 etc.
When it comes to == comparision, unfortunately there is no rule of thumb nor a clear logic. This is probably because the various forms of the operator were implemented by different programmers, without a central design decision. The best I can do is providing you with this graph to print and stick over the monitor:
The key of the grap is: A == B will be TRUE if and only if A and B are of two types directly connected by a line in the graph above. For instance, array() == NULL is TRUE because array() and NULL are directly connected, while array() == 0 is FALSE because there is no line connecting the two.
Lines marked in red are the tricky (non obvious) equalities.
I've omitted that each entity will be equal to itself (e.g. "1" == "1" etc.) but that should be easy to remember.
As a final note, I'd like to explain why "php" == 0 is TRUE (non empty, non number string is equal to 0): because PHP casts "php" to number before comparision and, since it's not a number, it defaults to 0 and makes the test TRUE.
Fun fact: there is no partition in this relation! If ever a transitive closure was allowed, you could easily say that True is False and False is True, destroying millennia of philosphy in four easy PHP statements :D
If the value contains something then it can be said to be true. For example, 1, 1.123, array("value"), etc. are all treated as true.
If the value can be said to be empty or void (i.e. lacking something) then it is seen as false. For example, 0, 0.0, array(), and so on.
This way of thinking about variables is not special to PHP. Many other languages do it in the same or similar way. E.g. Perl, C and Javascript, just to name a few.
There is imo a very straightforward guideline and a bug in the specification, which might be confusing.
Strict comparison checks equality in datatype and value.
Loose comparison checks equality in value only.
For an object (not part of the comparison table) is php quite straightforward:
if the object is the same instance as the other one, then is it strictly equal, otherwise might it be loosely equal.
Therefor is a 0 and a "0" loosely equal to each other and to false (and to any string). The latter can be understood as all strings are not numeric, hence false and the number that is equal to false is 0, hence all strings are equal to 0.
The comparison between null and array() is more complicated. If you check an array created with array() and compare that loosely and strictly, then will it return true. If you however check it with is_null, then will it return false. I think the latter is more logical, because an array() created with array() is not equal to '', where null is. I would think that this functional inconsistency between the function is_null() and the checks
== null or === null a bug, because it should not happen that using two different valid methods to check for a value return different results.
Null is also not an array according to the function is_array(), which is true. An empty array is an array according to the function is_array(), which should be true too. Hence should it never be true that null is equal to array().
There is no particular logic, but you can figure out some patterns.
"empty" values (null, false, 0, empty string and string '0') evaluate to false
comparison of numeric values is done implicitly converting them to integers until some version (there was a bug when two actually different long numeric strings counted as equal, now it's fixed)
when working with arrays, there is no difference between integer and numeric indexes, except when you call array_key_exists with explicit strict parameter
comparing number with string implicitly converts right argument to the type of the left one
return ($something); implicitly converts $something to string if it is not scalar
The base pattern is the same to the one used in C: anything non-zero is true for the sake of boolean comparisons.
In this sense, an empty string or array is also false.
The hairy scalar to look out for is '0', which is (very inconveniently) treated as empty too because it gets converted to an integer. array(0) is just as thorny on the array front.
When using strict comparisons (=== and !==), things are a lot more sane. In practice, it's often a good idea to cast input coming from superglobals and the database as appropriate, and to use these operators from that point forward.
I look at it the following way:
PHP is designed as a web programming language and all the input of the pages is based on strings [human-like perception] [This is by the way is also true for JavaScript]
Hence, all the strings which look like numbers (is_numeric() function), preliminary behave like numbers [comparison, casting].
That explains why extreme cases, like "0" are first implicitly thought to be cast to (int)0 and only then to false.
PHP is loosely Typed Language but could someone tell me, What is the default data type of any PHP variable? What is its implicit data Type?
PHP's variables are dynamic, and change depending on the data inside them. So they have no datatype by default.
From the manual on variables:
It is not necessary to initialize variables in PHP however it is a
very good practice. Uninitialized variables have a default value of
their type depending on the context in which they are used - booleans
default to FALSE, integers and floats default to zero, strings (e.g.
used in echo) are set as an empty string and arrays become to an empty
array.
So, they are what you make of them.
The OP understands that PHP is a loosely typed language and therefore the type of any initialized variable is determined by the data it holds; so read that way, the question then becomes What is the type of an uninitialized variable? - the answer to which is null
PHP doesn't generally allow you to declare variables without initializing them, there's no direct equivalent to:
Dim SomeVar
Therefore the only way to see that "default" data type is to evaluate either a variable that hasn't been set or a class member that holds no data.
1: A variable that hasn't been set
echo $someVar === null ? "NULL" : "NOT NULL"; //outputs NULL (and triggers a Warning)
2: A declared class member that holds no data
class Test {
public static $someVar;
}
var_dump(Test::$someVar); // outputs NULL
Therefore:
the type of any initialized variable is determined by the data it holds
the type of any uninitialized variable is null
Type Juggling
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. That is to say, if a string value is assigned to variable $var, $var becomes a string. If an integer value is then assigned to $var, it becomes an integer.
An example of PHP's automatic type conversion is the addition operator '+'. If either operand is a float, then both operands are evaluated as floats, and the result will be a float. Otherwise, the operands will be interpreted as integers, and the result will also be an integer. Note that this does not change the types of the operands themselves; the only change is in how the operands are evaluated and what the type of the expression itself is.
Source: http://www.php.net/manual/en/language.types.type-juggling.php
Even being relatively well aware of PHP peculiarities, the following strange behaviour still got me confused today:
// loose
$a = array(true => 'foo');
var_dump(array_key_exists(1, $a));
// strict
$a = array('7.1' => 'foo');
var_dump(array_key_exists('7.10', $a));
I wonder what could be the technical reason of this effect, so the question is, what in the process behind this function is causing values of some types to be compared loosely while others are compared strictly? I'm not complaining about the behaviour, but trying to understand that, so there is no point for "PHP sucks" comments.
In your first case, a boolean value is not a valid array key, so it is immediately turned into a 1 when you initialize the array, making your search match.
In your second case, the array key is a string, and '7.1' is not the same string as '7.10'
In your second example, '7.1' and '7.10' are strings. They are compared as string, so they don't match.
Now why do you have a match in the first example? Array keys can be either strings or integer. So true is converted to integer, which evaluates as 1.
This is documented here. Note that, keys are integers or strings. Specific key casts are mentioned in the documentation, in particular (for your case) that bools are cast to integers (ie. true as 1 and false as 0). As noted elsewhere, your other examples are strings (remove the quotes to make them floats, which would then be truncated to integers as per the docs).
maybe you could add the script output there? First glance though: Boolean as array key? I dont think thats gonna help in any way! 2nd: 7.10 is not the same at 7.1 - declaring this in '' makes it a string....
if you want true as a keyname, then you need to encapsulate it in either single or double quotes. IF you dont know about PHP and single/double quotes, it will cause the contents to be treated as a string value rather than Integer of Boolean (True/False)