位运算在PHP错误级别中的运用
首先,我们要解决的第一个问题是
什么是位运算?
按照wikipedia中的说法,位运算有如下的含义
- 位运算操作的是二进制数
- 对二进制数在位级别上进行运算
- 效率通常比普通的加减乘除快(为什么快的问题有待解决)
其次,我们要解决的问题是
什么是PHP的错误级别?
根据错误产生的原因,PHP将错误分成若干类,参见文档。每一种错误对应一个全局常量,可以用来组合,得到的结果作为参数传递给error_reporting()函数,PHP就能知道哪些错误应该被忽略,哪些错误应该被显示或记录日志。接下来,又引出一个问题
表示每一种错误的全局常量是如何被组合的?
在配置文件中的配置项error_reporting或者传递给error_reporting()的参数中,通过对表示错误的常量进行位运算来组合错误种类,从而决定要处理哪些错误。
假定有符号整型在机器上占4个字节,32位。我们先看看表示错误的全局常量和其对应值的十进制与二进制表示
| 常量 | 十进制 | 二进制 |
|---|---|---|
| E_ERROR | 1 | 00000000 00000000 00000000 00000001 |
| E_WARNING | 2 | 00000000 00000000 00000000 00000010 |
| E_PARSE | 4 | 00000000 00000000 00000000 00000100 |
| E_NOTICE | 8 | 00000000 00000000 00000000 00001000 |
| E_CORE_ERROR | 16 | 00000000 00000000 00000000 00010000 |
| E_CORE_WARNING | 32 | 00000000 00000000 00000000 00100000 |
| E_COMPILE_ERROR | 64 | 00000000 00000000 00000000 01000000 |
| E_COMPILE_WARNING | 128 | 00000000 00000000 00000000 10000000 |
| E_USER_ERROR | 256 | 00000000 00000000 00000001 00000000 |
| E_USER_WARNING | 512 | 00000000 00000000 00000010 00000000 |
| E_USER_NOTICE | 1024 | 00000000 00000000 00000100 00000000 |
| E_STRICT | 2048 | 00000000 00000000 00001000 00000000 |
| E_RECOVERABLE_ERROR | 4096 | 00000000 00000000 00010000 00000000 |
| E_DEPRECATED | 8192 | 00000000 00000000 00100000 00000000 |
| E_USER_DEPRECATED | 16384 | 00000000 00000000 01000000 00000000 |
| E_ALL | 32767 | 00000000 00000000 01111111 11111111 |
知道了要通过位运算组合错误种类,接下来的问题便是
如何通过位运算来组合出我们想要的错误种类?
首先,我们看看位运算符有哪些,参见文档
| 例子 | 名称 | 结果 |
|---|---|---|
| $a & $b | And(按位与) | 将把 $a 和 $b 中都为 1 的位设为 1。 |
| $a | $b | Or(按位或) | 将把 $a 和 $b 中任何一个为 1 的位设为 1。 |
| $a ^ $b | Xor(按位异或) | 将把 $a 和 $b 中一个为 1 另一个为 0 的位设为 1。 |
| ~ $a | Not(按位取反) | 将 $a 中为 0 的位设为 1,反之亦然。 |
| $a << $b | Shift left(左移) | 将 $a 中的位向左移动 $b 次(每一次移动都表示“乘以 2”)。 |
| $a >> $b | Shift right(右移) | 将 $a 中的位向右移动 $b 次(每一次移动都表示“除以 2”)。 |
利用这些运算符和预定义常量,就能对错误种类进行组合。假如,我们希望处理以下几种错误组合
- 所有错误都不处理
- 处理
E_ALL中除了E_NOTICE类型错误 - 只处理
E_ERROR和E_WARNING类型错误
第一个,显然要对E_ALL取反,即~E_ALL,二进制值运算式
1~ 00000000 00000000 01111111 11111111
结果为
111111111 11111111 10000000 00000000
所有类型错误对应的位均被置0,表示所有错误将不会被显示。
例程如下
1<?php
2ini_set('display_errors', true);
3error_reporting(~E_ALL);
4
5
6// E_NOTICE
7echo $var;
8
9// E_USER_DEPRECATED
10trigger_error ('deprecated error triggered', E_USER_DEPRECATED);
11
12// E_WARNING
13$a = 2048/0;
14
15// E_ERROR
16func();
运行,没有任何输出。
第二个,转换成位运算表示为E_ALL & ~E_NOTICE,对应的二进制运算式
1 00000000 00000000 01111111 11111111
2& 11111111 11111111 11111111 11110111
结果为
100000000 00000000 01111111 11110111
除了E_NOTICE对应的位为0,其他类型错误对应的位均为1,表示只有E_NOTICE不会被显示。
例程如下:
1<?php
2ini_set('display_errors', true);
3error_reporting(E_ALL & ~E_NOTICE);
4
5
6// E_NOTICE
7echo $var;
8
9// E_USER_DEPRECATED
10trigger_error ('deprecated error triggered', E_USER_DEPRECATED);
11
12// E_WARNING
13$a = 2048/0;
14
15// E_ERROR
16func();
运行,输出
1Deprecated: deprecated error triggered in /usr/local/var/www/test/index.php on line 10
2Warning: Division by zero in /usr/local/var/www/test/index.php on line 13
3Fatal error: Uncaught Error: Call to undefined function func() in /usr/local/var/www/test/index.php:16
除了E_NOTICE级别的错误,E_WARNING、E_ERROR和E_USER_DEPRECATED级别的错误均被显示。
第三个,转换成位运算表示为E_ERROR | E_WARNING,对应的二进制运算式
1 00000000 00000000 00000000 00000001
2| 00000000 00000000 00000000 00000010
结果为
100000000 00000000 00000000 00000011
E_ERROR和E_WARNING对应的位为1,其他类型错误对应的位为0,表示只有E_ERROR和E_WARNING类型的错误将被显示。
例程如下:
1<?php
2ini_set('display_errors', true);
3error_reporting(E_ERROR | E_WARNING);
4
5
6// E_NOTICE
7echo $var;
8
9// E_USER_DEPRECATED
10trigger_error ('deprecated error triggered', E_USER_DEPRECATED);
11
12// E_WARNING
13$a = 2048/0;
14
15// E_ERROR
16func();
运行,输出
1PHP Warning: Division by zero in /usr/local/var/www/test/index.php on line 13
2PHP Fatal error: Uncaught Error: Call to undefined function func() in /usr/local/var/www/test/index.php:16
除了E_NOTICE和E_USER_DEPRECATED级别的错误,E_WARNING和E_ERROR级别的错误均被显示。
以上,便是位运算在PHP错误级别中的运用。
其他需要探究的问题
- PHP为什么使用位运算处理错误级别的组合?
- 有没有其他类似的位运算应用?
- 为什么位运算速度快?