函数参数作为PHP中的位常量

哈Ha! 我向您介绍Liam Hammett的文章翻译: PHP中的位掩码常量参数

PHP包含许多标准函数,这些函数以带有二进制数字的内置常量的形式接受布尔参数。
这些值被组合到函数的单个参数中,以便以紧凑的方式传输多个布尔标志。


它们的工作方式可能与许多人在其代码中想象和使用的方式略有不同,因此我建议考虑一下它的实际工作方式。




如何在PHP函数中使用它


PHP 7.2(包括扩展名)包含1800多个预定义常量,其中一些用作函数的参数。
这样的应用程序的一个示例是PHP 7.3中的新选项,它允许您从json_encode函数引发异常以进行转换错误。


 json_encode($value, JSON_THROW_ON_ERROR); 

使用| (或)按位运算符,几个函数参数作为一个。 PHP文档中的一个示例


 json_encode($value, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP | JSON_UNESCAPED_UNICODE); 

没事


但是,它如何运作?


在用户定义函数的世界中,应用按位运算以实现相同的效果实际上很简单,但是至少需要了解什么是位以及PHP中按位运算的工作原理。


可以使用十进制(以10为底),十六进制(以16为底),八进制(以8为底)或二进制(以2为底)数字系统指定整数。 [...]
要使用二进制表示法,必须将数字0b放在前面。
-php.net

具有不同二进制数集的常量示例:


 const A = 0b0001; // 1 const B = 0b0010; // 2 const C = 0b0100; // 4 const D = 0b1000; // 8 

注意数字的示例和顺序。 每个二进制值最后代表每个零的两倍高的值。 0b和1之间的零是可选的,但可以帮助对齐源代码。


幸运的是,我们需要了解只有两个按位运算是如何工作的。


按位或


不要混淆操作员|按位“ OR” )与常用运算符||逻辑“ OR” ),通常在if else找到。
按位“或”是一种二进制运算,其作用等同于对位于操作数的二进制表示中相同位置的每对位应用逻辑“或” 。 换句话说,如果操作数的两个对应位均为0,则结果的二进制位为0;否则,结果为0。 如果该对中的至少一位为1,则结果的二进制位为1。


按位运算“ OR”的示例:


 const A = 0b0001; const B = 0b0010; const C = 0b0100; const D = 0b1000; A | B === 0b0011; A | C | D === 0b1101; 

按位与(AND)


同样,不应将&运算符( 按位AND )与经常使用的&&运算符( 逻辑AND )混淆。
按位与是一种二进制运算,其作用等同于对位于操作数的二进制表示中相同位置的每对位应用逻辑与 。 换句话说,如果操作数的两个对应位均为1,则结果二进制位为1;否则,结果二进制位为1。 如果该对中的至少一位为0,则所得二进制位为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 

一个数字可以有布尔值吗?


值得注意的是,在PHP中存在“类型操纵 ”( type juggling )的概念。 用非专家的语言来说,这意味着它(PHP)将在必要时自动尝试将一种类型的数据转换为另一种类型的数据。
如果您了解这种转换是如何发生的,那么这将是一个有用的工具。
例如,我们知道数字0转换为布尔值时将作为false ,而所有其他数字将为true 。 还记得我们使用的这些二进制值实际上是整数吗?


总结一下!


现在,我们可以结合这种知识来创建一个if构造,仅当数字之间按位运算的结果不是0b0000 (或0 ,它转换为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' 

其他内置的PHP函数(例如json_encode )以相同的方式工作。


值得吗?


也许您现在希望将这种方法应用于具有大量参与条件构造的参数的函数,但是在处理按位函数标志时有许多缺点:


  • 您不能通过参数传递非布尔值。
  • 没有使用docblocks记录参数的标准方法。
  • 您将失去对大多数IDE的一般提示和支持。
  • 相反,您可以将关联数组作为参数传递,以能够设置非零值(甚至是class )。
  • 有充分的理由说明为什么应避免将逻辑“功能标志”用作参数,而应将另一个函数或方法用于可变功能。

但是,现在您知道该怎么做了。




读取一长串常量定义可能是冗长且困难的,因此这里有一个辅助函数可以简化其定义。

Source: https://habr.com/ru/post/zh-CN423257/


All Articles