php strnatcasecmp() erratic behaviour - php

I'm trying to sort an array which has alphanumeric strings with different lenghts. I'm having some difficulties with this comparison:
>>> strnatcasecmp("IG2349", "IG56LR1617617")
=> 1
As you can see, the result states that "IG2349" is greater than "IG56LR1617617", so "IG56LR1617617" appears before "IG2349" after sorting.
But taking a look at the strings, after the two first characters (equals) the third is lower on the first string than on the second string, so the result should be < 1.
This is being tested on php 5.6.20.

Use binary safe comparison strcasecmp instead of natural:
strcasecmp("IG2349", "IG56LR1617617");

Related

Why does this happen in php when we multiple string by number it always gives zero(0)?

Suppose we have a string $str = "a"; and number $num = 2;
$str = 'a';
$num = 2;
echo $str*$num;
Output:
0
When performing arithmetic operations on a string operand, PHP will try to convert the string to a number.
It does this by looking for digits at the beginning of the string and will try to convert them into a value. If there are no digits, the value will be zero.
(There's an edge case for strings containing e or E (scientific notation), but that's not relevant here.)
Good Question.
Same i did ask to my teacher when i was in collage,
The answer is.
String * int= infinity; //According to scientific calculator answer is infinity.
but we need to continue our so program it provide 0.
it is made by code by default answer.
Simply said the string will be converted to an integer with a value of 0. This will include most of the cases when only alphabetic values are used. If you try to add a integer value at the beginning of the string it would in theory become a integer of that value.
I would recommend to read Why PHP Strings Equal Zero or Comparison Operators
Maybe you are looking for str_repeat, instead doing looping for that, its a default value that php serve to you, or you need to cast A into integer . When you try to do calculation for data that is not in Integer/float data type. Usually PHP auto-typecast the variables. In some cases it wont. Then we have to type cast it manually

PHP's Infinit value in Bitwise Operations returns strange values

Today I just made an interesting discovery while testing what happens calculating bitwisely in php like INF ^ 0 (^ => Bitwise Operator for Exclusive OR (XOR)) what gave me int(-9223372036854775808) => greatest possible negative value in a 64-Bit system.
But then I was asking myself: "Why is the result going negative in XOR when the "positive infinit" means 9223372036854775807 (63 Bits on 1 with a leading 0) and 0 (64 Bits on 0 => 0 xor 0 = 0) What is PHP's infinit value though and what is the calculation behind it? And why do I get a (correct?) negative value when I use "negative infinit"(A leading 1 against a leading 0 on 0 => 1 xor 0 = 1?".
Another interesting point is that this just happens on PHP Version 5.5.9-1, and not e.g. on 5.3.x. and 5.6.x (where i've tested it)! Maybe someone has an idea what happens there? Tested it on three versions but just mine (5.5.9-1) gives those results:
Just to let you guys know, it's just an abstract playaround i've done for fun but I find it's interesting. Maybe someone can help here or explain me a wrong thought I have? Just tell me if someone needs more informations about anything!
EDIT: Accordingly to jbafford it would be great to get a complete answere, so i'll just quote him: why does 5.5 and 5.6 result in PHP_INT_MIN, and everything else return 0?
First off, ^ itself isn't what's special here. If you XOR anything with zero, or OR anything with zero, you just get back the original answer. What you're seeing here is not part of the operation itself, but rather what happens before the operation: the bitwise operators take integers, so PHP converts the float to an integer. It's in the float-to-integer conversion that the weird behaviour appears, and it's not exclusive to the bitwise operators. It also happens for (int), for example.
Why does it produce these weird results? Simply because that's what the C code PHP is written in produces when converting a float to an integer. In the C standard, C's behaviour for float-to-integer conversions is undefined for the special values of INF, -INF and NAN (or, more accurately, for "integral parts" an integer can't represent: ยง6.3.1.4). This undefined behaviour means the compiler is free to do whatever it wants. It just so happens in this case that the code it generates produces the minimum integer value here, but there's no guarantee that will always happen, and it's not consistent across platforms or compilers.1 Why did the behaviour change between 5.4 and 5.5? Because PHP's code for converting floats to integers changed to always perform a modulo conversion. This fixed the undefined behaviour for very large floating-point numbers,2 but it still didn't check for special values, so for that case it still produced undefined behaviour, just slightly different this time.
In PHP 7, I decided to clean up this part of PHP's behaviour with the Integer Semantics RFC, which makes PHP check for the special values (INF, -INF and NAN) and convert them consistently: they always convert to integer 0. There's no longer undefined behaviour at work here.
1 For example, a test program I wrote in C to try to convert Infinity to an integer (specifically a C long) has different results on 32-bit and 64-bit builds. The 64-bit build always produces -9223372036854775808, the minimum integer value, while the 32-bit build always produces 0. This behaviour is the same for GCC and clang, so I guess they're both producing very similar machine code.
2 If you tried to convert a float to an integer, and that float's value was too big to fit in an integer (e.g. PHP_INT_MAX * 2, or PHP_INT_MIN * 2), the result was undefined. PHP 5.5 makes the result consistent, though unintuitive (it acts if the float was converted to a very large integer, and the most significant bits were discarded).
Your float(INF) gets implicitly casted to an Integer.
and XOR with 0 does not change the first parameter. So basically this is just a cast from float to int which is undefined for values which are not in the integer range. (for all other values it will be truncated towards zero)
https://3v4l.org/52bA5

Can anyone explain the length parameter to fgets() in PHP?

Assume that I have a file named data.txt with the contents "Blah Blah !".
So when I use the code below
$hnd=fopen('data.txt','r');
echo fgets($hnd,2);
it displays just one character "B" instead of "Bl". Later I read the manual stating:
length
Reading ends when length - 1 bytes have been read, or a newline (which is included in the return value), or an EOF (whichever comes first). If no length is specified, it will keep reading from the stream until it reaches the end of the line.
Can anyone explain to me why it is this way? I mean why is it length-1 and not length.
The C fgets() function reads length - 1 bytes, because it has to add a terminating zero to turn the data into a proper string.
My best guess is that PHP's fgets() exhibits the same behaviour because it is either:
a legacy from the bad old days when PHP functions were little more that wrappers around the corresponding C functions, and string functions were binary unsafe (eg. strings could not contain embedded NUL characters). Changing the behaviour of the fgets() function would introduce new bugs in existing programs. Or,
a deliberate decision to make the PHP function compatible with the C function to avoid unnecessary surprises.
or both.
Interestingly, it looks like PHP internally adds a terminating zero when storing string values, for example in _php_stream_get_line() (called from fgets()) and zend_string_init().
Since _zend_string objects store the string length anyway, it shouldn't be necessary to store the terminating zero, unless there are still binary unsafe functions in PHP.
Because PHP, like many C-derivatives count from 0, and not from 1. They have Zero-based numbering
Eg for arrays: An array of length/size n has 0 to n - 1, elements.
i.e. 0, 1, 2 , 3, 4 .... n-1
So an array of length 5 has elements 0, 1, 2, 3, 4
So you will find that whether reading byte, strings, arrays... they always reference the to the (n-1)th element or marker, for an n-size structure
Please use following code for your raised questionarries
$hnd=fopen('E:\\data.txt','r');
echo fgets($hnd,2);

How does PHP compare strings with comparison operators?

I'm comparing strings with comparison operators.
I need some sort of explanation for the below two comparisons and their result.
if('ai' > 'i')
{
echo 'Yes';
}
else
{
echo 'No';
}
output: No
Why do these output this way?
if('ia' > 'i')
{
echo 'Yes';
}
else
{
echo 'No';
}
Output: Yes
Again, why?
Maybe I forgot some basics, but I really need some explanation of these comparison examples to understand this output.
PHP will compare alpha strings using the greater than and less than comparison operators based upon alphabetical order.
In the first example, ai comes before i in alphabetical order so the test of > (greater than) is false - earlier in the order is considered 'less than' rather than 'greater than'.
In the second example, ia comes after i alphabetical order so the test of > (greater than) is true - later in the order being considered 'greater than'.
To expand on coderabbi's answer:
It is the same type of logic as when you order by number in some applications and get results like the following:
0
1
105
11
2
21
3
333
34
It's not based on string length, but rather each character in order of the string.
The < and > comparison operators in PHP will compare the first character of your string, then compare other characters that follows in the strings.
Therefore, your first expression ai (first string) and i (second string) a is the first character in the string compared with i as the first character in the second string with > will return false, and subsequently the second statement will return true due to the same reason.
However, if you really need to compare two longer string values with many characters, you may try using the substr_compare method:
substr_compare("abcde", "bc", 1, 2);
in this sample, you have your two strings to be compared, 1 is the offset start position, and 2 represents how many characters you want to compare to the right of those strings. -1 will means the offset start from the end of the first string. e.g. do something like this:
substr_compare("string1", "string2", 0, length);
also, consider using strcmp() also i.e. strcmp("string1", "string2", length) where length is number of character you want to compare from the two strings.
When both strings are in number format, PHP will convert the strings to numbers and convert the values.
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.
Reference: Comparison Operators

if(0 == '%') echo "WTF, Php, why can't you compare things sanely?"

I just reduced a crazy bug to what's in the title of this question.
I'm sure there's a Perfectly Reasonable Explanation for why Php thinks that 0 == '%' (or any other special character, I think).
I thought it would be good to get that explanation on StackOverflow!
It will do the same to any string, converting a non-number string to integer always gives 0.
Using '===' (for exact, literal comparison -- the values must be the same type and also equal) instead of '==' solves this problem. With '==' it's trying to cast '%' to a number and 0 is the best it can do.
In the event that a strict comparison operator is not directly suitable, if you want both values to be compared as strings, you can use strcmp(). An example could be where both values are variables, and the types might be either string, or int. Instead of type casting to string and then using strict equality check, strcmp() can be less verbose.
php's type coercion is very convenient. But if you don't understand its many rules(some can bite), you should try to avoid using it. See
http://www.php.net/manual/en/types.comparisons.php
since '%' isn't true, it ought to be false (0), so of course 0=='%'
;-) funny though
This is because it converts '%' to number and it is 0.
The way, however, how PHP converts strings to numbers is pure evil IMHO, because non number string does not have to result in zero.
If it starts with a digit then php will result the first number it can find in it and ignore the rest of the string. So:
"2 times 5 equals 10"
..will result in 2 when casted to a number.
Article in the documentation

Categories