I am padding integers for barcodes with leading zeros so they have same number of characters, for example:
1 -> 00000001
12 -> 00000012
1044 -> 00001044
00000001 is numeric and when casting to an integer it is 1.
Will this work as expected for all integers?
Careful, numbers starting with 0 are treated as base 8 in PHP
>> var_dump(011);
int(9)
however explicit casting string to int seems to be safe
>> var_dump((int)'011');
int(11)
You did not say anything where you're going to be storing these numbers, but in case it will be a database, here's some advice regarding datatype:
Barcode numbers are not (despite the name) numbers. Same goes for fax numbers, social security numbers, etc. You should not store these as numeric data (for example using MySQL's INT or DECIMAL) datatype. Instead use textual datypes (like CHAR or VARCHAR)
Unless you treat it as a string PHP will interpret 00000001 as simply the integer 1. If you want to treat your barcodes as a string, take care to cast them correctly because PHP might interpret them as integers due to type juggling.
Will this work as expected for all ints?
That depends on what you expect. Left-padding with zeros will never change the value. Regardless of the number, you can add any number of zeros to the left of the string and it will always be numeric, and it will always cast to the same integer.
(int)"01" == 1
(int)"0001" == 1
(int)"000000001" == 1
etc.
Related
I am using PHP 7.0.2
At one place in the manual on integers, I saw the below statement :
Integers can be specified in decimal (base 10), hexadecimal (base 16),
octal (base 8) or binary (base 2) notation, optionally preceded by a
sign (- or +).
and at one place in the manual I saw below contradictory statement :
PHP does not support unsigned integers.
Due to these two sentences I got confused. At one place it's saying that an integer can optionally be preceded by a sign which means whenever I use any integer, preceding it with a sign(- or +) or not will be my choice.
And at the same time it's saying that PHP does not support unsigned integers.
So, does it say that whenever I use any integer without preceding it with a sign(+ or -) won't it be considered as a legal integer in PHP?
To clarify this, just as an integer and a float are different data types, an unsigned integer is actually a different data type to an integer. A standard integer is usually 32 bits (this can vary between different programming languages) and can be from approx -2 billion to +2 billion, while an unsigned integer can be from 0 to approx +4 billion. You can also have smaller and larger integers, which have lower and higher max values, and can also be unsigned, keeping the same number of distinct options but shifting to only positive.
This is relevant for things like database key fields, where an unsigned integer is ideal for autoincrement identity type fields, but will not be properly supported in php. It gets complicated, so if you're just using php don't stress over it and if you're using php with a database provider it's probably best to avoid using unsigned integers in your data as php will either break or start returning negative values different to the positive value that's actually stored.
It's the sort of annoyance that makes my eye twitch a little.
That simply means, that each integer is signed and you can't create unsigned integers. So if you want to use something bigger than PHP_INT_MAX, you have to use strings (or some library like bcmath) to come around this.
The + prefix to state a positive integer is optional, positive integers can be indicated by no sign or a +. Negative integers can only be indicated by a -.
Extending the examples from the integer guide.
$a = 123; // decimal number (123)
$a = +123; // decimal number (123)
$a = -123; // a negative decimal number (-123)
$a = 0123; // octal number (equivalent to 83 decimal)
$a = +0123; // octal number (equivalent to 83 decimal)
$a = -0123; // octal number (equivalent to -83 decimal)
$a = 0x1A; // hexadecimal number (equivalent to 26 decimal)
$a = +0x1A; // hexadecimal number (equivalent to 26 decimal)
$a = -0x1A; // hexadecimal number (equivalent to -26 decimal)
$a = 0b11111111; // binary number (equivalent to 255 decimal)
$a = +0b11111111; // binary number (equivalent to 255 decimal)
$a = -0b11111111; // binary number (equivalent to -255 decimal)
Have played with hex values in PHP, but haven't understand this behavior yet
echo hexdec(0x80); //296
echo hexdec((string)0x80); //296
echo hexdec("0x80"); //128
hexdec() assumes its’s getting a string. In the first you’re taking a number 0x80, which is 128 in decimal, and giving it to it. This means it needs to be made into a string “128” because the default way to convert is the decimal form. When you then want that to be treated as hex it will become 296.
In the last one you actually say “here’s a string of a hex number, convert it to decimal” and the conversion is done.
Numeric literals aren’t handled as hex or dec or anything. They’re just numbers and hexdec() isn’t meant to be used with them. Only strings. This is where implicit conversions between types may cause issues.
here are some differents between string in php internal and at php layer.
0x80 is a numberic literal, it is same at the internal and language layer. it is 128 hexadecimal, convert to decimal is 296.
(string)0x80 looks like it will change to "0x80", but if you echo (string)0x80 it will output 128!!! and we know 0x80 is in Decimal is 128, so (string) action just change it to decimal string expression.
"0x80" is real string expression. it will calculate every charater to hex, so it will be (0 * 16 + x * 16 (igonre) + 8 *16 + 0 * 16) = 128.
all above is the numberic in php literal final store as decimal.
(string)number is also store decimal string expression.
Okay, so I understand that in the world of PHP—and this level of programming in general—ordinal values rule. So a number like 18 would simply be returned as 18 when generated in a PHP function. That makes sense to me. Base 10 numbers typically do not get left 0 padding by default.
But then comes along base_convert, dechex & decbin. Which each have the following format where a string is returned:
string base_convert ( string $number , int $frombase , int $tobase )
string dechex ( int $number )
string decbin ( int $number )
Which makes sense because values like these are not ordinal numbers in PHP:
ord 13 becomes hex d
ord 32 becomes bin 100000
Now these are technically correct values. But what doesn’t make sense to me is why each of the returned values doesn’t have left padding like this which seems to be more human readable to me:
ord 13 becomes hex 0d
ord 32 becomes bin 00100000
Is there some logical reason I am missing as to why there isn’t a left 0 padding option for binary & hex numbers generated via base_convert, dechex & decbin?
It seems to me a simple padding option could be added to the interface of each function? Possibly as simple as a true/false with perhaps options similar to str_pad. Or was such an option purposely left off due to the potential formatting rabbit hole of complexity adding such options would create? Meaning, “Just use str_pad since these are strings & not ordinal numbers so do with it as you wish.”
My code
<?php
var_dump('0xD' * 1 );
var_dump((int)'0xD');
var_dump(intval('0xD'));
var_dump((float)'0xD');
Actual result:
int(13)
int(0)
int(0)
float(0)
Why result of first two conditions are not same? Can you provide me correct documentation?
All that I found is
Type Casting: Type casting in PHP works much as it does in C: the name of the desired type is written in parentheses before the variable which is to be cast. It may not be obvious exactly what will happen when casting between certain types. For more information, see these sections:...
Converting to integer: From strings:
See String conversion to numbers
String conversion to numbers When a string is evaluated in a numeric context, the resulting value and type are determined as follows.
So, As far as I understand, docs say that casting to int directly and by putting in numeric context should be same. What is my mistake?
ADDED: Try to check first and second code (and outputs) before answering.
'0xD' is a string. The documentation clearly specifies how a string is "casted" into an integer value (picking the (int) '0xD'; example here):
When a string is evaluated in a numeric context, the resulting value and type are determined as follows.
If the string does not contain any of the characters '.', 'e', or 'E' and the numeric value fits into integer type limits (as defined by PHP_INT_MAX), the string will be evaluated as an integer. In all other cases it will be evaluated as a float.
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.
The initial porition of the string '0xD' that is a number is 0, hence the it's (int) 0.
Don't mix this with writing code. If you write that in code it's not a string, it's the hexa-decimal representation/notation of an integer number (Demo):
<?php
$value = eval("return 0xD;");
var_dump($value); # int(13)
This does not fully answer why the expression '0xD' * 1 results in (int) 13, but explains everything else so far and which two rules of integer value interpretation apply in PHP.
I assume that there is a slight difference between casting to integer and integer context in PHP. If the string representing a hexadecimal number it is used in integer/float context:
'0xD' * 1
In this expression, the string '0xD' will get evaluated as number because of the * operator and the 1 operand (see Type Juggling). This is not Type Casting, because there is no cast language construct.
It looks like that in this expression's case, the interpretation of the string as an integer is done literally (as specified) but is not the same as when you do a conversion.
One could argue it remains undocumented when conversion applies and when literal interpretation applies. However, using type casting can get you around any such problems (Demo):
<?php
$value = '0xD';
var_dump($value); # string(3) "0xD"
var_dump($value * 1); # int(13)
var_dump((int) $value * 1); # int(0)
It's the quotes, apparantly.
<?php
var_dump('0xD' * 1 );
var_dump((int) 0xD);
var_dump(intval(0xD));
var_dump((float) 0xD);
gives
int(13)
int(13)
int(13)
float(13)
I think PHP does not see the hex values in the strings as possible ints.
Does anyone know of an equivalent function in MySQL of PHP's base_convert?
http://php.net/manual/en/function.base-convert.php
Thanks,
Mark
CONV()
you could use CONV(N,from_base,to_base)
CONV(N,from_base,to_base)
Converts numbers between different number bases. Returns a string representation of the number N, converted from base from_base to base to_base. Returns NULL if any argument is NULL. The argument N is interpreted as an integer, but may be specified as an integer or a string. The minimum base is 2 and the maximum base is 36. If from_base is a negative number, N is regarded as a signed number. Otherwise, N is treated as unsigned. CONV() works with 64-bit precision.
http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_conv