Doctrine fromArray bug? - php

I have a problem with doctrine with this code I can't explain.
public function fromArray(array $array, $deep = true) {
$refresh = false;
foreach ($array as $key => $value) {
if ($key == '_identifier') {
$refresh = true;
$this->assignIdentifier($value);
continue;
}
My key (integer) 0 will equal (string) '_identifier'. Is this a bug in PHP or is this normal? or am I doing something wrong?
When I change the code to $key === '_identifier' it works. I have PHP version 5.3.4

That's PHP:
echo (int) '_identifier'; // 0
And 0 equals 0. In the comparison operation the string is changed into integer to compare it.
Use === to do a comparison of the same type as well. Called identical, not equal:
public function fromArray(array $array, $deep = true) {
$refresh = false;
foreach ($array as $key => $value) {
if ($key === '_identifier') {
$refresh = true;
$this->assignIdentifier($value);
continue;
}

As far as I understand:
== is just generic comparing, so if your key is an integer it will convert the string to an integer to compare it and from the manual:
The value is given by the initial
portion of the string. If the string
starts with valid numeric data, this
will be the value used. Otherwise, the
value will be 0 (zero). Valid numeric
data is an optional sign, followed by
one or more digits (optionally
containing a decimal point), followed
by an optional exponent. The exponent
is an 'e' or 'E' followed by one or
more digits.
=== is strict evaluation so it compares types too.
So when you do "0 == '_identifier'" it passes as it evaluated '_identifier' as 0.
When you do "0 === '_identifier'" it does not pass as they are different types.

Related

foreach, unexpected result for element, which key is 0

I have this code
$arr = array(
"0"=>"http://site.com/somepage/param1/param2/0",
"1"=>"http://site.com/somepage/param1/param2/1",
"thispage" => "http://site.com/somepage/param1/param2/2",
"3"=> "http://site.com/somepage/param1/param2/3"
);
foreach ($arr as $k=>$v) {
if ($k == "thispage") {
echo $k." ";
}
else {
echo ''.$k.' ';
}
}
Its surprise, for first element "0"=>"http://site.com/somepage/param1/param2/0", not created link, (for other elements works fine)
If replace first element key 0 on something other, for example 4, now links created. What is wrong ?
This is happening because 0 == "thispage" and the first key is 0. To find out more about this, take a look at the PHP manual page about Type Juggling.
Use === ("is identical to") instead of == ("is equal to"), because 0 is equal to "thispage", but not identical.
This is what happens with ==:
$key takes the integer value of 0
PHP tries to compare 0 == "thispage"
in order to make the comparison, it needs to cast "thispage" to integer
the resulting comparison is 0 == 0, which is true
If you use ===:
$key takes the integer value of 0
PHP tries to compare 0 === "thispage"
since 0 is of a different type (integer) than "thispage" (string), the result is false
This is What you are doing wrong.
if ($k === "thispage") {
echo .$k." ";
}
Do the:
if ($k === "thispage")
You have to use identical comparison operator === as equal comparison operator won't help here, because
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.
thispage converted to number will return 0, so your if statement will match if you use equal comparison operator ==. When you do identical comparison === if type does not match it returns false.
You can read about comparison operators here.
Try this:
if ($k === "thispage") {
echo $k." ";
}
http://us.php.net/manual/en/language.types.array.php:
A key may be either an integer or a string. If a key is the standard representation of an integer, it will be interpreted as such (i.e. "8" will be interpreted as 8, while "08" will be interpreted as "08").
So in your case Stings "1", "2" and "3" are treated as integers.
To fix this use the === operator that check for type along with value.
The reason for the result you see is the comparison operator you use. == is too imprecise sometimes and can result in wierd things like this. Using the === will compare the values for exactness and will prevent the issue you have.
so:
foreach ($arr as $k=>$v) {
// this is the important thing
if ($k === "thispage") {
echo $k." ";
}
else {
echo ''.$k.' ';
}
}

Weird $key => $value comparison with PHP

I'm facing a weird issue with PHP. This simple example:
<?php
$array = array(
'zero',
'one',
'id' => 'two'
);
foreach ($array as $key => $value) {
if ($key == "id") {
echo "Key: ". $key .", value: ". $value ."\n";
}
}
?>
should (imho) output this:
Key: id, value: two
But it outputs
Key: 0, value: zero
Key: id, value: two
How is this possible: 0 == "id"?
When $key is 0 and gets compared to the string "id", the string ("id") will be converted to an integer. Since "id" can't be turned into a valid integer that conversion will yield 0, and the if statement becomes true.
Since you don't want the implicit conversion to happen between two types who aren't compatible use the more strict === version of ==. === will see if the variables are of the same type and has the same exact value.
if ($key === "id") {
...
}
Documentation PHP: Comparison Operators
Examples
var_dump (0 == (int)"id");
var_dump ((string)0 == "id");
var_dump (0 === "id");
var_dump (1.0 === 1);
output
bool(true)
bool(false)
bool(false)
bool(false) # be careful!
You are being bitten by a process called type juggling.
Try the following:
var_dump(0 == "id");
It will output bool(true).
PHP is performing integer comparison, and when it attempts to convert the string "id" to an integer, the result is 0. PHP will happily parse leading digits of a string and stop at the first non-numeric value, yielding integer 123 for strings like "123xyz". Because there are no leading digits in the string "id", it is parsed as integer 0.
The solution is to use ===, which compares the value and type of two variables, without attempting to juggle the types of the operands.
This:
$key == 'id'
...will make PHP do integer comparison, since the lvalue is an integer.
If you're wondering why this:
if ($key) { ... }
...wouldn't give the same result, well it's because the lvalue here (while omitted) is boolean, equivalent to:
if (true == $key) { ... }
Therefore, PHP will attempt boolean comparison. You can use the === operator to force a type check.
You can refer to the Type Comparison Tables and the Comparison Operators Table.
If you set the logic expression to take into account vartype
if (key === "id")
if will work. Just like #refp says.

Why does (0 == 'Hello') return true in PHP?

Hey, if you have got the following code and want to check if $key matches Hello I've found out, that the comparison always returns true if the variable is 0. I've came across this when an array for a special key and wondered why it's wasn't working as expected.
See this code for an example.
$key = 1;
if ($key != 'Hello') echo 'Hello'; //echoes hello
$key = 2;
if ($key != 'Hello') echo 'Hello'; //echoes hello
$key = 0;
if ($key != 'Hello') echo '0Hello'; //doesnt echo hello. why?
if ($key !== 'Hello') echo 'Hello'; //echoes hello
Can anyone explain this?
The operators == and != do not compare the type. Therefore PHP automatically converts 'Hello' to an integer which is 0 (intval('Hello')). When not sure about the type, use the type-comparing operators === and !==. Or better be sure which type you handle at any point in your program.
Others have already answered the question well. I only want to give some other examples, you should be aware of, all are caused by PHP's type juggling. All the following comparisons will return true:
'abc' == 0
0 == null
'' == null
1 == '1y?z'
Because i found this behaviour dangerous, i wrote my own equal method and use it in my projects:
/**
* Checks if two values are equal. In contrast to the == operator,
* the values are considered different, if:
* - one value is null and the other not, or
* - one value is an empty string and the other not
* This helps avoid strange behavier with PHP's type juggling,
* all these expressions would return true:
* 'abc' == 0; 0 == null; '' == null; 1 == '1y?z';
* #param mixed $value1
* #param mixed $value2
* #return boolean True if values are equal, otherwise false.
*/
function sto_equals($value1, $value2)
{
// identical in value and type
if ($value1 === $value2)
$result = true;
// one is null, the other not
else if (is_null($value1) || is_null($value2))
$result = false;
// one is an empty string, the other not
else if (($value1 === '') || ($value2 === ''))
$result = false;
// identical in value and different in type
else
{
$result = ($value1 == $value2);
// test for wrong implicit string conversion, when comparing a
// string with a numeric type. only accept valid numeric strings.
if ($result)
{
$isNumericType1 = is_int($value1) || is_float($value1);
$isNumericType2 = is_int($value2) || is_float($value2);
$isStringType1 = is_string($value1);
$isStringType2 = is_string($value2);
if ($isNumericType1 && $isStringType2)
$result = is_numeric($value2);
else if ($isNumericType2 && $isStringType1)
$result = is_numeric($value1);
}
}
return $result;
}
Hope this helps somebody making his application more solid, the original article can be found here:
Equal or not equal
pretty much any non-zero value gets converted to true in php behind the scenes.
so 1, 2,3,4, 'Hello', 'world', etc would all be equal to true, whereas 0 is equal to false
the only reason !== works is cause it is comparing data types are the same too
Because PHP does an automatic cast to compare values of different types. You can see a table of type-conversion criteria in PHP documentation.
In your case, the string "Hello" is automatically converted to a number, which is 0 according to PHP. Hence the true value.
If you want to compare values of different types you should use the type-safe operators:
$value1 === $value2;
or
$value1 !== $value2;
In general, PHP evaluates to zero every string that cannot be recognized as a number.
In php, the string "0" is converted to the boolean FALSE http://php.net/manual/en/language.types.boolean.php

PHP Associative array

I have an array as
$arrTest = array('val1','val2','val3','val4');
$arrTest['lastKey'] = 'Last Key';
foreach($arrTest as $key => $val) {
if($key == 'lastKey') {
echo "last found";
}
}
The above code is not working. I have added associative element in the array. Could it be the reason?
Change == to === in:
if($key == 'lastKey')
Your existing code echos last found twice, once for key 0 and once for key lastKey.
Comparing integer 0 and string 'lastKey' using == returns true !!
From the PHP manual:
String conversion to numbers
When a string is evaluated in a
numeric context, the resulting value
and type are determined as follows.
The string will be evaluated as a
float if it contains any of the
characters '.', 'e', or 'E'.
Otherwise, it will be evaluated as an
integer.
The value is given by the initial
portion of the string. If the string
starts with valid numeric data, this
will be the value used. Otherwise, the
value will be 0 (zero). Valid numeric
data is an optional sign, followed by
one or more digits (optionally
containing a decimal point), followed
by an optional exponent. The exponent
is an 'e' or 'E' followed by one or
more digits.
Use === to compare. Because when key 0 will be compared with string lastKey, string will be converted to integer and false result will be returned.
http://codepad.org/5QYIeL4f
$arrTest = array('val1','val2','val3','val4');
$arrTest['lastKey'] = 'Last Key';
foreach($arrTest as $key => $val) {
if($key === 'lastKey') {
echo "last found";
}
}
Read more about differences: http://php.net/manual/en/language.operators.comparison.php
You need to change your equality condition to check the type as well.
if($key === 'lastKey')
This is because PHP evaluates ' ' == 0 as true.
When I ran your code, 'last found' was outputted twice. 'lastKey' is evaluated to 0 in PHP, so if($key == 'lastKey') actually matches twices: once for 0 and once for your special element.
use the end() function to get the last key of an array and compare it in your if statement.
$arrTest = array('val1','val2','val3','val4');
$lastKey = end($arrTest);
foreach($arrTest as $key => $val) {
if($val == $lastKey) {
echo "last found";
}
}
Your code is working fine :
see it here : http://codepad.org/hfOFHMnc
However use "===" instead of "==" as you might encounter a bug when
comparing the string with 0 , and it will echo twice.
<?php
$arrTest = array('val1','val2','val3','val4');
$arrTest['lastKey'] = 'Last Key';
print_r($arrTest);
foreach($arrTest as $key => $val) {
if($key == 'lastKey') { // use === here
echo "key = $key :: last found \n";
}
}
If you want to test if an array key exists, simply use array_key_exists:
array_key_exists('lastKey', $arrTest)
You could also use isset but note that it returns false if the value associated to the key is null.

php, mysql, arrays - if( x == 0 ) { }

I have the following code
while($row = $usafisRSP->fetch_assoc())
{
$hidden_keys = array('Applicantid', 'unique_num', 'regs_time' ....);
$hidden_fields = array_intersect_key($row, array_fill_keys($hidden_keys, NULL));
$hidden_values = array();
foreach ($hidden_fields as $key => $value) {
// fill the values array using the values from fields array
$hidden_values[$value] = "$key = ".base64_decode($value)."";
if(base64_decode($value)== 0)
{
$hidden_values[$value] = "";
}
echo $hidden_values[$value];
The question is about "if($hidden_values[$value] == 0)" ... Basically I want to do not display/echo the $hidden_values[$value] if it's value of $value is 0. Sometimes $value is 0 or some words like (23 avenue).
I think you ran into three catches with PHP type comparisons and equalities:
Any string not beginning with a number will always loosely equal 0. So basically, if(base64_decode($value)== 0) will likely always resolve to true, even if decoded $value is "Adam".
Return value of base64_decode is a string, so if 0 is the result, it will be string 0, not integer 0. This means if(base64_decode($value) === 0) wouldn't even work if decoded $value is "0". Another catch is base64_decode may return false on errors, again failing this strict equality check.
A non-empty string (other than "0") will always loosely equal true. So this is the only comparison you really need for your case.
I think this is what you want, replacing the last 5 lines...
if(base64_decode($value)) echo $hidden_values[$value];
else $hidden_values[$value] = "";
} // closing your for loop
Is this what you're looking for?
foreach( $hidden_values as $value ) {
if( $value !== 0 ) {
echo $value;
}
}

Categories