Hi, Habr! I present to you the translation of an article by Liam Hammett : Bitmask Constant Arguments in PHP .
PHP contains many standard functions that take boolean arguments in the form of embedded constants with values ​​of binary numbers.
These values ​​are combined into a single function argument in order to pass multiple Boolean flags in a compact manner.
They may work a little differently than many people imagine and use in their code, so I propose to consider how it actually works.
PHP 7.2, including extensions, contains over 1800+ predefined constants and some of them are used as function arguments.
One example of such an application is a new option in PHP 7.3 that allows you to throw an exception to the json_encode
function for conversion errors.
json_encode($value, JSON_THROW_ON_ERROR);
Using |
(or) bitwise operator; several function arguments work as one. Example from PHP documentation:
json_encode($value, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP | JSON_UNESCAPED_UNICODE);
Very nothing.
Using bitwise operations to achieve the same effect in the world of user-defined functions is actually simple, but it requires at least a basic knowledge of what bits are and how bitwise operations work in PHP.
Integers can be specified in decimal (base 10), hexadecimal (base 16), octal (base 8) or binary (base 2) number system. [...]
To write in binary notation, you must put in front of the number 0b.
- php.net
Examples of constants with a different set of binary numbers:
const A = 0b0001; // 1 const B = 0b0010; // 2 const C = 0b0100; // 4 const D = 0b1000; // 8
Pay attention to the example and sequence of numbers. Each binary value represents a value twice as high for each zero at the end. Zeros between 0b and 1 are optional, but may help align the source code.
Fortunately, we need to understand how only two bitwise operations work.
Do not confuse the operator |
( bitwise "OR" ) with the frequently used operator ||
( logical "OR" ), which is commonly found in if else
.
Bitwise "OR" is a binary operation, the action of which is equivalent to applying a logical "OR" to each pair of bits at the same positions in the binary representations of the operands. In other words, if both the corresponding bits of the operands are 0, the binary bit of the result is 0; if at least one bit of the pair is 1, the binary bit of the result is 1.
An example of a bitwise OR operation:
const A = 0b0001; const B = 0b0010; const C = 0b0100; const D = 0b1000; A | B === 0b0011; A | C | D === 0b1101;
Similarly, the &
operator ( bitwise “AND” ) should not be confused with the frequently used &&
operator ( logical “AND” ).
Bitwise "AND" is a binary operation, the action of which is equivalent to applying a logical "AND" to each pair of bits at the same positions in the binary representations of the operands. In other words, if both corresponding bits of the operands are 1, the resulting binary bit is 1; if at least one bit of the pair is 0, the resulting binary bit is 0.
const A = 0b0001; const B = 0b0010; const C = 0b0100; const D = 0b1000; const VALUE = 0b1010; A & B === 0b0000; // A B A & C & D === 0b0000; // A, B C A & A === 0b0001; // A A & VALUE === 0b0000; // A VALUE B & VALUE === 0b0010; // 1 B, VALUE
It is worth noting that in PHP there is the concept of "type manipulation " ( type juggling ). In the language of non-specialists, this means that he (PHP) will automatically try to convert data of one type to another, if necessary.
If you understand how such transformations occur, then this can be a useful tool.
For example, we know that the number 0
acts as a false
when converting to a boolean (boolean) type, while all other numbers will be true
. Remember that these binary values ​​we work with are actually integers?
Now we can combine this knowledge to create an if construct, the code in which will be executed only if the result of the bitwise operation between the numbers is not 0b0000
(or 0
, which is converted to false
).
const A = 0b0001; const B = 0b0010; function f($arg = 0) { if ($arg & A) { echo 'A'; } if ($arg & B) { echo 'B'; } } f(); // nothing f(A); // 'A' f(B); // 'B' f(A | B); // 'AB'
By the same principle, other PHP built-in functions (for example json_encode
) work.
Perhaps you now have a desire to apply this approach to functions with a large number of arguments that participate in conditional constructions, but there are a number of drawbacks in the processing of bitwise function flags:
However, now you know how to do it.
Reading a long list of definitions of constants can be verbose and difficult, so here’s an auxiliary function that simplifies their definition.
Source: https://habr.com/ru/post/423257/
All Articles