最近看了不少编码方面的文章,所以分二篇博文说下“PHP、字符串、编码、UTF-8”相关知识,本篇博文是上半部分,分为四大块内容,分别是“字符串的定义和使用”、“字符串转换”、“PHP 字符串的本质”、“多字节字符串”。上半部分比较基础,下一篇文章《PHP 与 UTF-8的最佳实践》可能干货更多一点。
PHP 中能够通过四种方法设置字符串:
单引号字符串
单引号字符串类似于 Python 中的原始字符串,也就是说单引号字符串没有变量解析功能和特殊字符转义功能。比如$str='hello\nworld',其中的\n并没有换行功能。
双引号字符串
双引号字符串具备单引号字符串没有的变量解析功能和特殊字符转义功能。
个人对于十六进制和八进制的字符串特殊转义很感兴趣,特别补充:
1
2
|
\[0-7]{1,3} #八进制表达方式
\x[0-9A-Fa-f]{1,2} #十六进制表达方式
|
heredoc
这种表达式类似于 Python 中的长字符串,能够定义包含多行的字符串。其语法定义很严格,使用起来需要注意。
1
2
3
4
|
$str=<<<EOD
hello\n
world
EOD;
|
Nowdoc
Nowdoc类似于单引号字符串,不会解析变量。比较适合定义一大段文本且无需对其中的特殊字符进行转义。
变量解析
PHP字符串最强大的部分就是变量解析,可以在运行时根据上下文解析变量(这才是解释型语言),可以产生很多妙用。
简单的变量解析就是在字符串中可以包含“变量”,“数组”,“对象属性”,复杂的语法规则就是使用{}符号来进行操作(组成一个表达式)。
通过一个例子看看变量解析的强大之处
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
classbeers {
constsoftdrink ='softdrink';
publicstatic$ale='ale';
public$data=array(1,3,"k"=>4);
}
$softdrink="softdrink";
$ale="ale";
$arr=array("arr1","arr2","arr3"=>"arr4","arr4"=>array(1,2));
$arr4="arr4";
$obj=newbeers;
echo"line1:{$arr[1]}\n";
echo"line2:{$arr['arr4'][0]}\n";
echo"line3:{$obj->data[1]}\n";
echo"line4:{${$arr['arr3']}}\n";
echo"line5:{${$arr['arr3']}[1]}\n";
echo"line6:{${beers::softdrink}}\n";
echo"line7:{${beers::$ale}}\n";
|
PHP 语言比 Python 简单的另外一个原因就是类型的隐式转换,会简化很多操作,这里通过字符串转换来说明。
字符串类型强制转换
1
2
3
|
$var= 10 ;
$dvar= (string)$var;
echo$dvar."_".gettype($dvar);
|
strval()函数是获取变量的字符串值:
1
2
3
|
$var= 10.2 ;
$dvar=strval($var) ;
echogettype($var) ."_".$dvar."_".gettype($dvar);
|
settype()函数是设置变量的类型:
1
2
3
|
$str="10hello";
settype($str,"integer");
echo$str;
|
在强制类型转换过程中,将其他类型的值转换为字符串的时候会遵循一定的规则,比如一个布尔值 boolean 的 TRUE 被转换成 string 的 “1”。相关规则最好还是理解下。
自动类型转换
上面的二个转换属于显示转换,而更要关注的是自动类型转换,在一个需要字符串的表达式中,会自动转换为类型,具体见例子:
1
2
3
|
$bool= true;
$str= 10 +"hello"
echo$bool."_".$str;
|
引用 PHP 文档的解释:
PHP 中的 string 的实现方式是一个由字节组成的数组再加上一个整数指明缓冲区长度。并无如何将字节转换成字符的信息,由程序员来决定。字符串由什么值构成没有限制,包括值为 0 的字节可以出现在字符串的任何位置。
PHP并不特别指明字符串的编码,那字符串到底是怎样编码的呢,这取决于程序员。字符串会按照 PHP 文件的编码来对字符串进行编码。比如你的文件编码是 GBK,那么你代码内容都是 GBK的。
补充二进制安全这个概念,其值为 0 (NULL)的字节可以处于字符串任何位置,而 PHP 的部分非二进制函数底层是调用的 C 函数,会把 NULL 后面的字符忽略。
只要 PHP 的文件编码是能兼容 ASCII 的,那么字符串操作就可以很好的被处理。但是字符串操作本质上还是 Native 的(不管文件编码是什么),所以在使用的时候需要注意:
一般情况下,虽然 PHP 内部不支持 Unicode 字符,但是支持 UTF-8 编码,绝大部分情况下不会有什么问题,但是下列的情况可能就处理不了了:
那么如何解决该问题呢? PHP 提供了 mbstring 扩展 !
mbstring 扩展默认不是打开的,安装的时候需要 --enable-mbstring。
我们首先看看 PHP.INI 中对于 mbstring 指令的配置,花了好久才逐步明白。
后面看看 mbstring 扩展的一些函数:
重点说明下:PHP 文件支持的编码有一定要,要兼容 ASCII。
但是不要使用 BIG-5 作为 PHP 文件编码,尤其字符串以 identifiers 或 literals 形式出现,假如实在 PHP 文件编码要是 BIG-5,那么对于输入输出的内容尽量转换为 UTF-8。
最后说下 Zend Multibyte 这个概念,理解的不是特别深刻,首先不要和 mbstring 扩展混在一块。 Zend Multibyte 模式默认是关闭的,可以通过 zend.multibyte 指令打开。然后通过 declare() 函数来指定 PHP 解析器的编码。
那这个指令出现的意义是什么?上面说过 PHP 文件的编码需要是兼容 ASCII 的,那么类似于 BIG-5 这样的非兼容 ASCII 编码怎么办,可以通过这个指令来操作,当 PHP 解析器读取 mbstring.script_encoding 编码并用该编码来解析 PHP 文件。