位运算在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为什么使用位运算处理错误级别的组合?
- 有没有其他类似的位运算应用?
- 为什么位运算速度快?