Difference between "==" and "strcmp" in PHP - php

I was asked to create simulation array_keys function, but check equality "==" returns false.
But with "strcmp ($a, $b) == 0" return true.
class Utility
{
public function convertArrayKeys(array $array)
{
$i = 0;
$elements = [];
foreach ($array as $element=>$value) {
$elements[] = ' ' . $i++ . " => '" . $element . "'";
}
return 'array ( ' . implode(', ', $elements) . ', )';
}
public function testStrings(array $array)
{
$arrayOur = $this->convertArrayKeys($array);
$arrayPhp = var_export(array_keys($array),true);
if ($arrayOur == $arrayPhp){
echo 'They are identical :)';
} else {
echo 'They are not identical :(';
echo '<br>';
print_r(str_split($arrayOur));
echo '<br>';
print_r(str_split($arrayPhp));
}
}
}
View:
$repository = array('box'=>'blue', 'cube'=>'red', 'ball'=>'green');
$utility = new Utility();
echo "OUr array_keys: ";
echo $utility->convertArrayKeys($repository);
echo "<br />";
echo "PHP array_keys: ";
print_r (var_export(array_keys($repository)));
echo "<hr >";
echo "<br />";
echo $utility->testStrings($repository);
I would appreciate to know because

Edit: The reason that the two don't work in THIS instance is that your functions dont produce identical outputs: yours produces:
array ( 0 => 'box', 1 => 'cube', 2 => 'ball', )
where the php function produces:
array (
0 => 'box',
1 => 'cube',
2 => 'ball',
)
If you were to view that in the web browser i think the web browser renderer does whitespace trickery. However try putting uhh <pre> tags around it (or run in command line to check).
Basically == does more then compare the two values - the documentation suggests "after type juggling". You can get some weird things by comparing strings using ==. One good example is: '1e3' == '1000'. It is useful to use ==at times, but possibly not in conjunction with strings.
Strcmp also though doesn't return a true/false answer, but a -1, 0, 1 answer indicating which string is alphabetically in front of the other.
You should also look at === which can also have helpful uses, but personally I would stick with strcmp with strings.

Hi never use == in PHP. It will not do what you expect. Even if you are comparing strings to strings, PHP will implicitly cast them to floats and do a numerical comparison if they appear numerical.
try these you will know the reason
$something = 0;
echo ('password' == $something) ? 'true' : 'false';// true
$something = 0;
echo ('password' === $something) ? 'true' : 'false'; // false
echo strcmp('password123',$something); // 1

Because they are not arrays, rather they are strings. Arrays are not created like this. you are doing it wrong. Were they arrays then
if ($arrayOur == $arrayPhp)
would have evaluated to true. But they are just strings and
"strcmp ($a, $b) == 0"
Does not return true, because there are whitespaces in the first string,
return 'array ( ' . implode(', ', $elements) . ', )';
You are doing it completely wrong. You need to correct your approach.

Related

PHPUnit: expect method call with array as argument

I have a PHPUnit test case, in which I am puzzled by the following snippet. I want to check that the method actionUpload calls the function exposeAndSaveDataLines correctly, i.e. that the first argument is an array as I expect it to be.
public function test_actionUpload()
{
$sut = $this->getMockBuilder('MasterdataController')
->setMethods(array('exposeAndSaveDataLines', 'render'))
->disableOriginalConstructor()
->getMock();
$expectedLines = require_once ($this->dataDir . 'expectedLines.php');
$sut->expects($this->once())
->method('exposeAndSaveDataLines')
->with($this->equalTo($expectedLines),
$this->anything(),
$this->anything(),
$this->anything(),
$this->anything());
$sut->actionUpload();
}
The expected data is a printout of the current array, made with a temporary print_r (var_export($lines)) in the actual code. I return it in the file expectedLines.php, and when I manually print it, it is correct.
Now, when I run the test case with a single character deliberately misspelled in expectedLines, I get the following error (as expected).
Failed asserting that two arrays are equal.
--- Expected
+++ Actual
## ##
3 => 'Colour Group Code'
- 4 => '{2F30E832-D3DB-447E-B733-7BC5125CBCCc}'
+ 4 => '{2F30E832-D3DB-447E-B733-7BC5125CBCCC}'
)
)
)
However, when I correct the mistake, it still mentions that the two arrays are not equal. However, it now prints the entire array (at least the start of it, it is a long array), but it doesn't show any differences (no - and + in front of any line). Why does the expects method not recognize that the two arrays are the same? How am I able to test this properly?
EDIT 1
I have shortened the array, such that it prints the entire array when they are not equal. Still no + or - signs in the comparison.
This is the end of my expectation PHP file.
'RetTarget Area' => array(
0 => array(
0 => '',
1 => '',
2 => '{C19D52BC-834C-45DA-B17F-74D73A2EC0BB}
'
),
1 => array(
0 => '1',
1 => '1',
2 => '{5E25C44F-C18A-4F54-B6B1-248955A82E59}'
)
)
);
This is the end of my comparison output in the console.
'RetTarget Area' => Array (
0 => Array (
0 => ''
1 => ''
2 => '{C19D52BC-834C-45DA-B17F-74D73A2EC0BB}
'
)
1 => Array (...)
)
)
I find it suspicious that the last Array is not fully shown in the comparison.
EDIT 2
I find here that the order of the arrays is important. I am pretty sure though I have all elements in the same order, if PHP is not doing something secret under the hood. The solution mentioned there I cannot copy, since I don't have a $this->assertEquals but a ->with($this->equalTo syntax.
EDIT 3
I read here about an undocumented parameter $canonicalize that orders arrays before comparing. When I use it like this:
$sut->expects($this->once())
->method('exposeAndSaveDataLines')
->with($this->equalTo($expectedLines, $delta = 0.0, $maxDepth = 10, $canonicalize = true, $ignoreCase = false),
$this->anything(),
$this->anything(),
$this->anything(),
$this->anything());
I see that the order of the arrays is indeed changed, but I still see the same error. Also, still one array is 'collapsed', which I suspect causes this failure. Besides, I don't want to order all my subarrays, they should be in the same order in the real and expected result.
--- Expected
+++ Actual
## ##
Array (
0 => Array (
0 => Array (
0 => ''
1 => ''
2 => '{C19D52BC-834C-45DA-B17F-74D73A2EC0BB}
'
)
1 => Array (...)
)
EDIT 4
When I use identicalTo instead of equalTo, I get a more elaborate error message, saying that the one array is not identical to the other array, while printing both of them. I copy-pasted them both into a text file, and used the command diff to check for any differences, but there were none. Still, PHPUnit claims that the two arrays are not equal/identical.
EDIT 5
When I use greaterThanOrEqual or even greaterThan instead of equalTo, then the test passes. This does not happen for lessThanOrEqual. This implies that there is a difference between the two arrays.
If I manually change the expected outcome into something with a string that is alphabetically before the correct string, I can lessThan pass as well, but then of course greaterThanOrEqual fails.
EDIT 6
I am getting convinced that the line ending of the strings in my array are making this comparison to fail, which doesn't show up in all comparisons.
I now have the following assertion.
public function test_actionUpload_v10MasterdataFile()
{
....
$sut->expects($this->once())
->method('exposeAndSaveDataLines')
->will($this->returnCallback(function($lines) {
$expectedLines = include ($this->dataDir . 'ExpectedLines.php');
$arrays_similar = $this->similar_arrays($lines, $expectedLines);
PHPUnit_Framework_Assert::assertTrue($arrays_similar);
}));
$sut->actionUpload();
}
private function similar_arrays($a, $b)
{
if(is_array($a) && is_array($b))
{
if(count(array_diff(array_keys($a), array_keys($b))) > 0)
{
print_r(array_diff(array_keys($a), array_keys($b)));
return false;
}
foreach($a as $k => $v)
{
if(!$this->similar_arrays($v, $b[$k]))
{
return false;
}
}
return true;
}
else
{
if ($a !== $b)
{
print_r(PHP_EOL . 'A: '. $a. PHP_EOL . 'Type: ' . gettype($a) . PHP_EOL);
print_r(PHP_EOL . 'B: '. $b. PHP_EOL . 'Type: ' . gettype($b) . PHP_EOL);
}
return $a === $b;
}
}
With the following result.
A: {72C2F175-9F50-4C9C-AF82-9E3FB875EA82}
Type: string
B: {72C2F175-9F50-4C9C-AF82-9E3FB875EA82}
Type: string
I finally got it to work, although it is a bit of a compromise. I am now removing newlines before I compare the arrays. This cannot be done in the with method, so I have made the following construction.
public function test_actionUpload_v10MasterdataFile()
{
/*
* Create a stub to disable the original constructor.
* Exposing data and rendering are stubbed.
* All other methods behave exactly the same as in the real Controller.
*/
$sut = $this->getMockBuilder('MasterdataController')
->setMethods(array('exposeAndSaveDataLines', 'render'))
->disableOriginalConstructor()
->getMock();
$sut->expects($this->once())
->method('exposeAndSaveDataLines')
->will($this->returnCallback(function($lines) {
$expectedLines = include ($this->dataDir . 'ExpectedLines.php');
PHPUnit_Framework_Assert::assertTrue($this->similar_arrays($lines, $expectedLines));
}));
// Execute the test
$sut->actionUpload();
}
...
private function similar_arrays($a, $b)
{
/**
* Check if two arrays have equal keys and values associated with it, without
* looking at order of elements, and discarding newlines.
*/
if(is_array($a) && is_array($b))
{
if(count(array_diff(array_keys($a), array_keys($b))) > 0)
{
return false;
}
foreach($a as $k => $v)
{
if(!$this->similar_arrays($v, $b[$k]))
{
return false;
}
}
return true;
}
else
{
$a = rtrim($a);
$b = rtrim($b);
$extended_output = false;
if ($extended_output && ($a !== $b))
{
print_r(PHP_EOL . 'A: '. $a. PHP_EOL . 'Type: ' . gettype($a) . PHP_EOL);
print_r(PHP_EOL . 'B: '. $b. PHP_EOL . 'Type: ' . gettype($b) . PHP_EOL);
}
return $a === $b;
}
}

echo a number in php

I am trying to learn php, and I am playing around with while loops. I was wondering how to print out a specific number in an array in php. Fx:
$a = [1,3,5,7,9,11,13];
$s = 3;
while($a == 3) {
echo $s.' is in the row';
$a++;
}
In this example I would like to run through the $a and see if 3 exist there. If it does it has to echo '3 is in the row' I tried to make a while loop, but it is not correct. Can anyone see what I am doing wrong? Just to say it, I think it is very wrong, but I don't know how to solve it, if I have to use the while loop?
Best Regards
Mads
Your while condition reads: "While the value of $a equals 3", but $a is an array, so its value can't ever be 3. The loop will never be executed. In PHP, we would write:
if (in_array($s, $a))
echo $s, ' was found in the array';
Or, if you insist on writing loops:
foreach ($a as $key => $value)
{
if ($value == $s)
{
echo $s, ' was found at offset ', $key;
break;//end terminate loop
}
}
Of course, you could also write:
for ($i=0, $j=count($a);$i<$j;++$j)
{
if ($a[$i] == $s)
{//you could move this condition to the loop itself, even
echo $s, ' found in array at offset ', $i;
break;
}
}
You can, if you want use a while loop, too, but that wouldn't be the best choice for your particular case. Just read through the manual on php.net. There are many, many array_* functions available, and there are many ways to iterate over your data.
Another worry is your using the array name as a sort-of C-style pointer: $a++; in C, an pointer can be incremented to set it to point to the next value in an array (if the new memory address is valid, and the pointer is valid, and all of the other things you have to worry about in C). PHP does not work this way. An array isn't really an array: it's a hash map. incrementing an array, therefore, is pointless and most likely to be a bug. The for loop is the closest you can get to traversing an array using the ++ operator.
You're looking for in_array. This checks if a value exists in an array, in the form of:
in_array ( mixed $needle , array $haystack )
So, in your case, you'd want to do:
$a = [1,3,5,7,9,11,13];
$s = 3;
if (in_array($s, $a)) {
echo $s.' is in the row';
}
foreach($a as $b) {
if($b == 3)
echo $b.' is in the row';
}
Modify slightly your code changing while condition:
$a = array(1,3,5,7,9,11,13);
$s = 3;
$counter = 0;
while($counter < count($a)) {
if ( $a[$counter] == $s )
echo $s.' is in the row';
$counter++;
}
Added counter to iterate through while loop until end of array.
count() method returns number of items in array.
This solution prints all occurences of your number.
To have better code, change names of variables:
$numbers = array(1,3,5,7,9,11,13);
$target = 3;
$counter = 0;
while($counter < count($numbers)) {
if ( $numbers[$counter] == $target )
echo $target.' is in the row';
$counter++;
}
There are two ways to do it,
First, you can loop through all items in the array using a foreach() loop.
That way, you can go through them all and if you have multiple conditions, it makes your code a bit more readable.
And example of that loop is like this:
foreach($array as $array_item) {
if($array_item === 3) {
echo "3 is in the array";
}
}
The alternative is to use a built in function to find if something is in the array. THis is probably much faster, though I haven't benchmarked the difference.
if(in_array(3, $array)) {
echo "3 is in the array";
}
you can use
array_search ,in_array , and forearch or for loops to itertate through the array.
For learning purposes
$a = [1,3,5,7,9,11,13];
$s = 3;
for($i=0;$i<count($a);$i++)
{
if($a[$i]==$s){
echo $s.' is in the row';
}
}
of course in real life
if (in_array(3, $a)) {
// Do something
}
would be better;
<?php
$a = [1,3,5,7,9,11,13];
$s = 3;
for($a=0;$a < 20; $a++)
{
while($a == 3) {
echo $s.' is in the row';
//$a++;
}
}
?>

How to format var_export to php5.4 array syntax

There are lots of questions and answers around the subject of valid php syntax from var outputs, what I am looking for is a quick and clean way of getting the output of var_export to use valid php5.4 array syntax.
Given
$arr = [
'key' => 'value',
'mushroom' => [
'badger' => 1
]
];
var_export($arr);
outputs
array (
'key' => 'value',
'mushroom' =>
array (
'badger' => 1,
),
)
Is there any quick and easy way to have it output the array as defined, using square bracket syntax?
[
'key' => 'value',
'mushroom' => [
'badger' => 1
]
]
Is the general consensus to use regex parsing? If so, has anyone come across a decent regular expression? The value level contents of the arrays I will use will all be scalar and array, no objects or classes.
I had something similar laying around.
function var_export54($var, $indent="") {
switch (gettype($var)) {
case "string":
return '"' . addcslashes($var, "\\\$\"\r\n\t\v\f") . '"';
case "array":
$indexed = array_keys($var) === range(0, count($var) - 1);
$r = [];
foreach ($var as $key => $value) {
$r[] = "$indent "
. ($indexed ? "" : var_export54($key) . " => ")
. var_export54($value, "$indent ");
}
return "[\n" . implode(",\n", $r) . "\n" . $indent . "]";
case "boolean":
return $var ? "TRUE" : "FALSE";
default:
return var_export($var, TRUE);
}
}
It's not overly pretty, but maybe sufficient for your case.
Any but the specified types are handled by the regular var_export. Thus for single-quoted strings, just comment out the string case.
For anyone looking for a more modern-day solution, use the Symfony var-exporter, also available as a standalone library on composer, but included in Symfony by default.
composer require symfony/var-exporter
use Symfony\Component\VarExporter\VarExporter;
// ...
echo VarExporter::export($arr)
I realize this question is ancient; but search leads me here. I didn't care for full iterations or using json_decode, so here's a preg_replace-based var_export twister that gets the job done.
function var_export_short($data, $return=true)
{
$dump = var_export($data, true);
$dump = preg_replace('#(?:\A|\n)([ ]*)array \(#i', '[', $dump); // Starts
$dump = preg_replace('#\n([ ]*)\),#', "\n$1],", $dump); // Ends
$dump = preg_replace('#=> \[\n\s+\],\n#', "=> [],\n", $dump); // Empties
if (gettype($data) == 'object') { // Deal with object states
$dump = str_replace('__set_state(array(', '__set_state([', $dump);
$dump = preg_replace('#\)\)$#', "])", $dump);
} else {
$dump = preg_replace('#\)$#', "]", $dump);
}
if ($return===true) {
return $dump;
} else {
echo $dump;
}
}
I've tested it on several arrays and objects. Not exhaustively by any measure, but it seems to be working fine. I've made the output "tight" by also compacting extra line-breaks and empty arrays. If you run into any inadvertent data corruption using this, please let me know. I haven't benchmarked this against the above solutions yet, but I suspect it'll be a good deal faster. Enjoy reading your arrays!
With https://github.com/zendframework/zend-code :
<?php
use Zend\Code\Generator\ValueGenerator;
$generator = new ValueGenerator($myArray, ValueGenerator::TYPE_ARRAY_SHORT);
$generator->setIndentation(' '); // 2 spaces
echo $generator->generate();
As the comments have pointed out, this is just an additional syntax. To get the var_export back to the bracket style str_replace works well if there are no ) in the key or value. It is still simple though using JSON as an intermediate:
$output = json_decode(str_replace(array('(',')'), array('&#40','&#41'), json_encode($arr)), true);
$output = var_export($output, true);
$output = str_replace(array('array (',')','&#40','&#41'), array('[',']','(',')'), $output);
I used the HTML entities for ( and ). You can use the escape sequence or whatever.

php multidimensional array syntax

The code below has two commented-out variations on one line. They produce rather different results, as you'll see if run them - without the space between $array and [$key], the individual letters of the key are mapped out to the array values.
Can someone explain what's happening here and why?
Thanks!
<?php
$letters = array('A','B','C');
$numbers = array(1,2,3);
$matrix = array('Letter' => $letters, 'Number' => $numbers);
foreach($matrix as $array => $list)
{
echo '<ul>';
foreach($list as $key => $value)
// {echo "<li>$array [$key] = $value ";}
// {echo "<li>$array[$key] = $value ";}
echo '</ul>';
}
"$array[$key]" is interpreted as the array access (value of $array[$key]). Same as echo $array[$key];.
"$array [$key]" is interpreted as two different variables: $array and $key. Same as echo $array." [".$key."]";.
The reason for the difference in output is due to the way that PHP parses strings containing variables.
If you change:
{echo "<li>$array [$key] = $value ";}
to
{echo "<li>" . $array [$key] . " = $value ";}
It will result in the same thing and the line below it.
{echo "<li>$array[$key] = $value ";}
PHP is mostly whitespace agnostic, but not inside of strings where intrinsically whitespace matters.
remember that "double quotes" tries to execute your code, while "single quotes" deals your code as text only.
in this case:
echo "<li>$array[$key] = $value ";
this code is being evaluated. here is saying something like "put this value in this position of this array". in the other hand, this:
echo "<li>$array [$key] = $value ";
isn't being evaluated because, to php, doens't make sense to it's parser assign a value to something like this:
[$someting] = $value;
the above code returns a fatal error.
your code doesn't return a fatal error because php tries to handle your code in some way that doesn't throw an exception.
the last example of your code (the one with spaces) is the same as this:
echo '<li>' . $array . '[' . $key . '] = ' . $value;
in short: want to show some variable in some string? put the variables off the php string's interpretation:
echo $myvar . ' = ' . $myvalue;

PHP elseif statement not executed even though initial if statement is false

I am writing a recursive function to print out the differences between 2 multildimensional php arrays. The purpose of this code is to see the difference between jpeg headers to deteremine how adobe bridge cs3 is saving rating information within the jpg file.
When I am single-stepping through the code using my eclipse - zend debugger ide, it appears that even though the initial if statement is false (ie neither values is an array), the subsequent elseif statements are never executed. The function is attached below.
Note: Changes since original post based on comments
Added a default level= ''
Removed comments between the if{} elseif{} blocks
Removed an else; at the end of the block that had no function
Encoded the < and > symbols so angle bracket would show in my code
function array_diff_multi($array1,$array2,$level=''){
$keys = array_keys($array1);
foreach($keys as $key)
{
$value1 = $array1[$key];
if(array_key_exists($key,$array2) ){
$value2 = $array2[$key];
if (is_array($value1) && is_array($value2)){ // Check if they are both arrays, if so recursion is needed
array_diff_multi($value1,$value2,$level . "[ " . $key . " ]");
}
elseif(is_array($value1) != is_array($value2)){ // Recursion is not needed, check if comparing an array to another type
print "<br>" . $level . $key ."=>" . $value1 . "as array, compared to ". $value2 ."<br>";
}
elseif($value1 != $value2){ // the values don't match, print difference
print "<br>" . $level . $key ."=>" . $value1 ." != " . $value2 ."<br>";
}
}
else{
print "<br>" . $level. $key . "does not exist in array2";
}
}
}
could it be because you have
else;
at the end...?
Try removing that or turning that into 'real code'
It works fine for me here. I put your function (with the tiny difference of adding a default value of '' to the level parameter), and these two arrays:
$a1 = array('foo', 'bar', 2, array('baz', '3', 4, array(54,45)));
$a2 = array('faz', 'bar', 4, array('buz', '3', 5, 54));
And got this output:
0=>foo != faz
2=>2 != 4
[ 3 ]0=>baz != buz
[ 3 ]2=>4 != 5
[ 3 ]3=>Arrayas array, compared to 54
Perhaps your starting arrays are not what you think they are...?
This doesn't exactly answer your question, but I think Adobe Bridge saves metadata in dotfiles in the same directory as the files. For example, sort information is saved in a .bridgesort file.
The only way that all the elseifs would be skipped is if the two variables are not arrays and are equal.

Categories