Python: What is the equivalent of PHP "==" - php

The question says it.
Here's a little explanation.
In PHP. "==" works like this
2=="2" (Notice different type)
// True
While in python:
2=="2"
// False
2==2
// True
The equivalent for python "==" in php is "==="
2===2
//True
2==="2"
//False
Million dollar question. What is php "==" equivalent to in python?

Python doesn't coerce between types the way PHP does, mostly.
You'll have to do it explicitly:
2 == int('2')
or
str(2) == '2'
Python coerces numeric types (you can compare a float with an integer), and Python 2 also auto-converts between Unicode and byte string types (to the chagrin of many).

There isn't one. You need to convert types before checking for equality. In your example, you could do
2==int("2")

There is no equivalent.
The difference is simply that Python is strong-typed where PHP is not, so a comparison between two types in Python would always return false. Unless you explicitly cast to the type of the other part of the comparison of course.

You could also have
str(2) == "2"

so here is the equivalent to php's ==
def php_cmp(a, b):
if a is None and isinstance(b, basestring):
a = ""
elif b is None and isinstance(a, basestring):
b = ""
if a in (None, False, True) or b in (None, False, True):
return bool(a) - bool(b)
if isinstance(a, (basestring, int, long, float)) and isinstance(b, (basestring, int, long, float)):
try:
return cmp(float(a), float(b))
except ValueError:
return cmp(a,b)
if isinstance(a, (tuple,list)) and isinstance(b, (tuple,list)):
if len(a) != len(b):
return cmp(len(a),len(b))
return cmp(a,b)
if isinstance(a, dict) and isinstance(b, dict):
if len(a) != len(b):
return cmp(len(a),len(b))
for key in a:
if key not in b:
raise AssertionError('not compareable')
r = cmp(a[key], b[key])
if r: return r
return 0
if isinstance(a, (basestring, int, long, float)):
return 1
if isinstance(b, (basestring, int, long, float)):
return -1
return cmp(a,b)
def php_equal(a, b):
return php_cmp(a,b) == 0
Test:
>>> php_equal(2, '2')
True
Due to a different object model and array implementation this is not 100% correct, but should give you some idea which problems might occur with automatically converting types for comparison.

May be this's something similar:
x = 5
y = "5"
str(x) == str(y)
True
str(2) == str("2")
True

The best answer one can give you is to avoid PHP-like comparison. Anyway, it leads you to hard-to-find errors and hours spent on debugging.
But it's okay if you want to write your own PHP interpreter in Python.
You probably want to cast variables first and compare them after. If you program fails on casting, you run into errors earlier preventing further damage.

Additional note
As an add-on to Martijn's answer ... since Python does not do implicit type coercion like PHP, you can use:
type(2)
or
type("2")
or
type(<expression>)
if you need to know the relevant type that Python uses internally, in order to do your expressly specified type coercion.

Related

strcmp vs. == vs. === in PHP for checking hash equality

I'm using crypt() to hash passwords in PHP, and am trying to work out the safest way of testing equality of the resulting hash when performing password checks.
There are three options that I can see:
Option 1 - Double Equals
function checkPassword($hash, $password)
{
return crypt($password, $hash) == $hash;
}
Option 2 - Triple Equals
function checkPassword($hash, $password)
{
return crypt($password, $hash) === $hash;
}
Option 3 - strcmp()
function checkPassword($hash, $password)
{
return strcmp(crypt($password, $hash), $hash) === 0;
}
My intuition tells me that option 1 is a bad idea, due to the lack of type checking, and that options 2 or 3 are likely to be better. However, I can't work out if there's a specific case that === or strcmp would fail under. Which is safest for this purpose?
When it comes to security I prefer to use the === operator. === ensures the two operands are exactly the same, without trying to accomodate some casting in order to "help" the comparison to reach a successful match - as it may help while developing thanks to a loose-typed language, like PHP.
Of course, one of the operand is to be trusted. A hash from the database is trustable, while the user input is not.
One can always dither for a while, coming to the conclusion there is no risk using == in a specific case. Maybe. But for instance
"0afd9f7b678fdefca" == 0 is true
"aafd9f7b678fdefca" == 0 is also true
as PHP tries to convert the "hash" into a number (probably using atoi) which gives 0. While it is unlikely crypt returns 0, I'd prefer to maximize the cases where the passwords don't match (and answer a support call) by using ===, than allowing a rare case that I didn't think about by using ==.
As for strcmp, the function returns <0 or >0 if different, and 0 if equal. But
strcmp("3", 0003) returns 0
strcmp("0003", 0003) returns -3
which are not surprising after all. A literal 0003 is actually an integer, 3 and since strcmp expects a string, the 3 will be converted to "3". But that shows there is some conversion that may happen in this case, since strcmp is a function, while === is part of the language.
So my preference in that case goes to === (which is faster than == anyway).
You should be using the hash_equals() function that is built into PHP. There would be no need to make your own function. The hash_equals() will return a boolean value.
In my opinion it is usually NOT a good idea to use == or === for comparing strings let alone hashed strings.
That is incorrect, please look at the definition of the function.
According to PHP:
Returns < 0 if str1 is less than str2;
> 0 if str1 is greater than str2,
and 0 if they are equal
It returns less than 0 if str1 is less than str2. Note the phrase "less than", it does not return just -1, but any negative value. The same happens when str1 is greater than str2, but it returns a positive, non-zero value. It returns a positive value that can be 1, or any number thereafter.
strcmp()returns a number that is the difference between the two strings starting with the last character that was found to be similar.
Here is an example:
$output = strcmp("red", "blue");
The variable $output with contain a value of 16
I think that using == would be sufficient in your case.
== checks for equality regardless of type, whereas === checks for equality as well as type.
1 == "1" = True
1 === "1" = False
Since we're not too concerned with type, I'd keep it simple and go with ==.

php string comparison unexpected type juggling

I encountered a strange and unexpected behavior in PHP while comparing some string values. The first two statements below return true when I would expect them to return false. The last statement returns false as expected. I'm aware of PHP's Type Juggling, but what I understand from the docs is that type juggling happens when you are comparing two different data types like a string and an integer. In the examples below though both literals are strings. Does this mean that when you are doing string comparison in PHP it inspects both strings to see if they look like integers and if so type casts the both of them to integers and then compares those integer values. So my question is under what conditions does this behavior happen, how exactly does string comparison work in PHP?
var_dump("10" == "10.0000");
var_dump("10" == "+10.");
var_dump("10" == "10 ");
#output
bool(true)
bool(true)
bool(false)
Updates
So baba's answer below comparison involves numerical strings really helped in getting me to understand what's going on. The function is_numeric will return to you whether or not a string is considered to be a numeric string. interestingly "10 " is not considered a numeric string but " 10" is. I dug around the PHP source code and I believe the implementation of is_numeric is in the is_numeric_string_ex function. From that one can tell exactly when PHP will treat a string as a numeric string.
You are getting error because of the position of the space this would return true
var_dump("10" == " 10"); // true
So if you RUN
var_dump("10" == "10 "); //false
What you are actually Running is because it would be treated as a string
var_dump("10" == 0); //false
This is because Type juggling would convert "10 " to 0 this is in the PHP Documentation
FROM PHP DOC
TRUE if $a is equal to $b after type juggling.
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.
If you want to trick type juggling
var_dump("10" == 0 + "10 "); // true
This is Because
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.
I suppose the definite answer lies buried somewhere in the vastness of
compare_function
in php-src/Zend/zend_operators.c and the macros used in there.
In this case, all the 'strings' except the last one, are treated like floats or integers, and then compared. Thats why line 1 and 2 give a true.
In line 3 there is a space in the string, and that means for php that is is a 'real' string, and that line gets strings compared.
I do not like loose typed languages either, but for php this is the way it works.

Weird behaviour with if statement

The following appears to work, yet I really don't think it should:
if ("'True','False'" == 0)
{
echo 'Hello, World.';
}
Is it grepping the last False out of the string, and if so why, and how do you stop it?
This is due to loose typing. When you compare a string to a number, PHP has to cast one to the other's type. In this case, the string, when casted to an integer, is worth 0, your condition being True.
Any string evaluates to 0 when being compared against a number (unless it's a stringed number such as "5" or "4string"). That's why it'll always evaluate to 0.
See the Type Comparison Table
What's really happening is that PHP is trying to do an implicit type conversion, and for one reason or another it's deciding that string when converted to an integer looks like 0. You can prove this to yourself by doing:
echo ((int) "'True','False'");
If you want to do a type-checked comparison you should use the triple equals (===):
if("'True','False'" === 0)
...which will most certainly evaluate to false.
No; it's converting the string "'True','False'" to a number — and that number is 0. 0 == 0 is true. You can solve it by using !"'True','False'" if I understand your intent correctly, or by using strict equality, ===, which you should generally use.

Very illogical php value comparisons

I stumbled upon a very strange bit of PHP code. Could someone explain why this is happening? *****BONUS POINTS***** if you can tell my why this is useful.
<?php
if(0=='a'){
print ord(0)." should NEVER equal ".ord('a')."<br>";
}
if(false==0){
print "false==0<br>";
}
if('a'==false){
print "a==false<br>";
}
?>
And the resulting output:
48 should NEVER equal 97
false==0
In PHP, 'a' is not the ASCII character a, but the string a. In a numeric context, it is equal to 0. For instance intval('a') results in a value of 0.
This is useful because PHP is primarily used for processing text, and one might want to try the test (123 == '123'), which is true. And given that a number in single (or double) quotation marks is treated as the number, it doesn't make sense for a string with no numeric value to be treated as anything other than 0.
Oh yeah, one more thing. 'a' in a boolean context is true, not false. I believe this makes some types of text processing more natural, but I honestly can't think of an example at this late hour.
Well, there's always the PHP type cheat sheet for that!
This is a basic principle of weakly/dynamically typed languages called type juggling. Types will be cast to other types in certain circumstances. When you compare a string to a number, the string will be cast into a number. When comparing anything to a boolean, that value will be cast to a boolean.
There are rules for every type as to how it will be cast into another type or how it compares to other types. 'a' happens to be converted to 0 when cast to a number (the only logical choice, really). To avoid this type casting, test not with the equality operator ==, but with the identity operator ===.
As James pointed out, this is useful since PHP deals a lot with strings that are really numbers. For example, HTML forms only submit strings, even if the value is a number. It also allows for some really terse code, like:
$result = someOperation();
if (!$result) {
// $result may be null, false, 0, '' or array(),
// all of which we're not interested in
error();
}
It also means you have to be really careful about what to check for in which circumstances though, since a value might unexpectedly cast into something else. And admittedly, 'a' == 0 in itself is really a pitfall of type juggling rather than helpful. It's one of the situations where you have to be careful and test like if (is_numeric($var) && $var == 0).
ord() takes characters, so PHP turns 0 into '0'. And 0 is equal to false, even though it is not identical (===).
Check out the PHP type comparison tables from the manual. It's a really handy thing to have close at hand until you've internalised it and has been invaluable to my understanding of exactly what will evaluate to true and when.
Others have already answered the core of the question, but I think it's important to state that in PHP, the only non-empty string that does not evaluate to "true" with the == operator is "0" as PHP treats any string containing only numbers as an integer or float.
The rationale for this is that PHP is fairly loosely typed and tries to allow integers, strings, floats and boolean values to be interchangeable. A real-world and extremely common example of this is if you're using the mysql or PDO functions, strings are returned for everything, even if the underlying column is an integer.
Consider the following sql:
CREATE TABLE `test`.`pants` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`some_other_int` INT NOT NULL
) ENGINE = InnoDB;
INSERT INTO `test`.`pants` (`id`, `some_other_int`)
VALUES ('1', '1'), ('2', '0');
And the following code:
<?php
$c = mysql_connect('127.0.0.1', 'user', 'password');
mysql_select_db('test', $c);
$r = mysql_query('SELECT * FROM pants', $c);
while ($row = mysql_fetch_assoc($r)) {
var_dump($row);
foreach($row as $k=>$v) {
if (!is_string($v))
echo "field {$v} was not a string!\n";
}
}
The "field x was not a string!" message is never printed, even though every column in the database is an integer. Suppose you want to actually use the second row in that table.
<?php
$id = 2;
$r = mysql_query(sprintf('SELECT * FROM pants WHERE id=%s', mysql_real_esacpe_string($id)), $c);
$row = mysql_fetch_assoc($r);
// this is the important bit
if (0 == $row['some_other_int']) {
echo "It was zero!";
}
If the string "0" was not treated as the integer 0 for the comparison, the above code would never print "It was zero!". The programmer would be required to take responsibility for juggling the type of the value which comes out of the database. This is not desirable for a loosely typed language.
Strict equality including type is tested using the "Is really, truly, honest to god equal to" operator, which is represented by the symbol "===".
I don't see how ('a'==0) is helpful
$var = '123abc';
if (123 == $var)
{
echo 'Whoda thunk it?';
}
It comes down to PHP's implicit conversion rules.
I'm failing at thinking of a practical example, but that's the basic reason why you're seeing that behavior.
Expansion:
In your example, 'a' is converted to 0 (zero), for the comparison. Imagine that for the purpose of the comparison, it's equivalent to '0a'. (That's the numeral zero, not the letter 'o.')
Further expansion:
I thought there was a good example use case for this in the manual, but I failed to find it. What I did come across should help shed some light on this "illogical" situation.
PHP is first and foremost a Web
language, not a general-purpose
scripting language. Since the Web is
not typed and everything is a string,
I had to do things slightly
differently early on to make PHP do
what people expected. Specifically,
"123"==123 needs to be true in order
to not have to type cast every single
numeric user input.
http://bugs.php.net/bug.php?id=48012
That doesn't exactly answer the question, but it points in the general direction.
PHP is a loosely typed language, and allows you to compare values of different types without throwing errors, which makes it very easy to use but as you have found can cause some weird but logical outputs.
Your first example:
if(0=='a'){
print ord(0)." should NEVER equal ".ord('a')."<br>";
}
When two different types of values are compared, one value is first turned into the same type as another via a cast and then compared. In the example of Int and String the string is converted into Int. When PHP turns a letter into a string it takes all the first numeric characters and then chops of the rest: i.e '123123afraa' becomes 123123, '9a9' becomes 9. If the string does not start with numerals it is given the value of 0.
Therefor your example is really: 0===(string)'a' which is really 0===0 since 'a' does not start with a numeric. I think you were expecting PHP to return the value of 'a' in ASCII which it does not! This is really useful to sanitise strings, php rarely needs to deal with ascii values it is too high level for that. (Its for making websites!)
When a string is compared to a boolean a value of '' or '0' are false, all other values are true. This is useful so you can check if a value is 'empty':
url http://domain.com/?foo=
if ($_GET['foo']))
{
// do something
}
When an integer is compared to a boolean the values of 0 is false other values are true, this is pretty standard.
So, all in all you need to understand what happens when different types of variables are compared with the == operator. Also it is probably wise to realise that == is almost never what you want and using === (which will not typecast your values) is ALOT safer.
The code seems to emanate from a unit test for the purpose of catching failures, hence the seemingly weird comparisons. In the same light, it may be preparatory to the main unit test to confirm that the == operator is working properly - as it should.

Understanding PHP & (ampersand, bitwise and) operator

I often use ($var & 1) in my code, which returns true if $var is an odd number and false if it's an even number.
But what does "&" actually do?
& is binary and. If you have a binary value, and you and with another binary value, then the result will be the bitwise and of the two. An example:
01101010
& 01011001
= 01001000
The rightmost bit is either a 1 (and in that case the number is an odd number) or it is a 0, in which case the number is even. If you & a number with 1, you only look at the least significant bit, and the if checks if the number is a 1 or a 0. As others have mentioned, look at the bitwise operators for info on how they work.
Two operations which are fundamental to binary systems are OR and AND.
OR means 'if either A is on or B is on'. A real world example would be two switches in parallel. If either is allowing current through, then current passes through.
AND means 'if both A and B is on'. The real world example is two switches in series. Current will only pass through if both are allowing current through.
In a computer, these aren't physical switches but semiconductors, and their functionality are called logic gates. They do the same sorts of things as the switches - react to current or no current.
When applied to integers, every bit in one number is combined with every bit in the other number. So to understand the bitwise operators OR and AND, you need to convert the numbers to binary, then do the OR or AND operation on every pair of matching bits.
That is why:
00011011 (odd number)
AND
00000001 (& 1)
==
00000001 (results in 1)
Whereas
00011010 (even number)
AND
00000001 (& 1)
==
00000000 (results in 0)
The (& 1) operation therefore compares the right-most bit to 1 using AND logic. All the other bits are effectively ignored because anything AND nothing is nothing. An even number in binary is also an even number in decimal notation (10 is a multiple of 2).
Other fundamental operations to binary systems include NOT and XOR. NOT means 'if A is off' and is the only form of logic gate that takes only one signal or 'parameter' instead of two. XOR means 'if either A or B is on, but not both'. And then there are NAND, NOR, and NXOR, which are basically just NOT combined with AND, OR, and XOR, ie NAND means 'if A and B are not both on'.
In programming, the operator
& means AND,
| means OR,
~ means NOT, and
^ means XOR.
The others can be made up by combining these, for example:
~ (a & b) is equivalent to a NAND operation
PHP specific note
Bitwise operators do not work on floating-point values, and in PHP float values will be implicitly converted to integers first. Numbers outside the range that can be expressed as integers will be truncated to zero - that is, all numbers over PHP_INT_MAX will look "even" in the expression ($num & 1)). If you want to support numbers outside of PHP_INT_MIN/PHP_INT_MAX, you'll need fmod($num, 2). If, however, you're on 64-bit PHP your integers will have greater precision than floats anyway.
This is also interesting to know about bitwise and PHP:
/**
* Regular
*/
echo (true && true); // 1
echo (true && false); // nothing
echo (true || false); // 1
echo (false || false); // nothing
echo (true xor false); // 1
echo (false xor false); // nothing
/**
* Bitwise
*/
echo (true & true); // 1
echo (true & false); // 0
echo (true | false); // 1
echo (false | false); // 0
echo (true ^ false); // 1
echo (false ^ false); // 0
I know your question is about understanding the bitwise operator and the accepted answer explains it well. But for the example you give, I cannot help but recommending you use the modulo operator instead:
($var % 2) /* instead of */ ($var & 1)
Because it makes the intent clear that you are checking that the number is odd (not divisible by two), and it is more generic, so you can use ($var % 3) the same way and deduce how it works for any N.
In addition to the other answers, it's worth noting that
if(func1() && func2())
Will only call func2() if func1() returns true ("lazy evaluation"), whereas
if(func1() & func2())
Will call both functions regardless, but the truth tables for both will be the same (assuming they return booleans).
thomasrutter points out (in the comments below) that you probably shouldn't do the latter in practice. (A & B) won't necessarily have the same truthiness as (A && B), particularly when A and B are integers. e.g., if A=1 and B=2 (both truthy), A & B will be falsey, whereas A && B is truthy. Also, another developer may think this is a typo and 'correct' it to two ampersands.

Categories