用GBK编码写PHP代码会发生什么事情?

环境

Windows 10
PHP 7.4

前言

在互联网领域,UTF-8编码已经几乎成为了标配,无论是网页、数据库还是代码文件等等,都广泛使用UTF-8作为编码方式。我平时写PHP代码时,文件的编码也都是使用UTF-8,今天突然想尝试一下,如果使用其它编码,会有什么后果呢?

实验

1. CLI环境
<?php
$str = '你';
var_dump($str);

编写以上代码,并且将文件的编码设置为GBK,然后在CMD命令行中运行此代码,最后显示结果是中文乱码:
在这里插入图片描述

经详细测试,只有在windows 10系统上,使用PHP 7.1(含)以上的PHP版本在CMD命令行中运行时,才会乱码,为什么会这样呢,目前我也不清楚…

接下来我们修改下代码,这次我们不将内容var_dump出来,而是将内容写入到一个text.txt文件里:

$str = '你';
file_put_contents(__DIR__ . '/test.txt', $str);

再执行代码,然后用type命令查看text.txt文件的内容,发现居然没乱码:
在这里插入图片描述

为什么var_dump出来会乱码,而写入到文件后再查看就不会乱码呢?因能力有限,这个问题目前还没弄清楚原因,后续有结果再更新:(

2. web环境

在CLI环境中会乱码,那在web页面中呢?答案是也会乱码:
在这里插入图片描述
但是我们可以通过设置一个响应头解决这个问题:

$str = '你';
header('Content-type: text/html; charset=gb2312');
var_dump($str);

再查看网页内容,已经不乱码了:
在这里插入图片描述

3. zend.multibyte

web环境可以通过设置响应头解决问题,那CLI环境呢?经过一番研究,发现可以通过修改php.ini文件来解决:
在这里插入图片描述
zend.multibyte参数设置为On,通过上方的英文描述,我们可以得知,这个参数开启后,就可以使用PHP解释器不兼容的编码来编写代码,例如CP936、Big5等等(注:CP936就是常说的GBK编码)。并且使用这个参数需要mbstring扩展。

然后在我们的代码文件中,添加一行declare(encoding="cp936")的代码:

<?php
declare(encoding="cp936");
$str = '你';
var_dump($str);

最后再运行此脚本,已经不乱吗了:
在这里插入图片描述
如果你的PHP脚本很多,不想每个文件都添加declare(encoding="...")的话,可以通过设置php.inizend.script_encoding配置项来解决,当PHP代码中没有设置declare(encoding="...")时,会默认使用zend.script_encoding的编码。
在这里插入图片描述

4. 其它
  • 如果PHP文件编码是UTF-16或UTF-32,则必须开启zend.multibyte,否则代码会无法执行,但无需像GBK那样在代码中添加declare(encoding="...")

这是因为默认情况下,PHP解析器是以ASCII编码来解析代码的,因此文件编码必须兼容ASCII,这里的兼容是指字符编码值一致,且存储空间也一致,例如GBK、UTF-8就符合这个要求。而在UTF-16中,所有字符是使用2个字节存储的,UTF-32是4字节,ASCII是1个字节,存储空间不一致导致不兼容。因此如果用UTF-16/UTF-32作为文件编码的话,必须开启zend.multibyte,这样PHP解析器才能正确解析源代码并且执行。

  • 如果PHP文件编码是UTF-8,则什么都不用做,也不会出现乱码

总结

经过上面简单的测试,已经出现了这么多的问题,因此平时做开发真的不要用非UTF-8的编码来写PHP代码!

后续需继续研究的问题:

  1. 使用UTF-16、UTF-32编码,为什么开启zend.multibyte后,无需像GBK编码那样添加 declare(encoding="...")
  2. 使用GBK编码,为什么中文var_dump出来会乱码,而写入文件后再查看却不会乱码?
  3. UTF-8跟GBK一样,都属于多字节的编码,为什么UTF-8在没有开启zend.multibyte的情况下,输出中文不会乱码,而GBK会乱码?而且还是在windows命令行环境默认是GBK编码的情况下,就更加诡异

参考文章

  1. GBK编码PHP脚本导致语法错误(Zend Multibyte)
  2. zend.multibyte官方文档
  3. What does zend.multibyte directive exactly affect?
  4. Is it true that string literals in PHP can only be encoded in an encoding which is a compatible superset of ASCII, such as UTF-8 or ISO-8859-1?
  5. PHP Strings官方文档
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值