0

0

双引号是否过多,这就是问题所在!

WBOY

WBOY

发布时间:2024-08-16 18:24:27

|

417人浏览过

|

来源于dev.to

转载

最近我又听说 php 人们仍然在谈论单引号和双引号,并且使用单引号只是一种微观优化,但如果你习惯一直使用单引号,你会节省大量的 cpu 周期!

“一切都已经说过了,但还没有被所有人说”——karl valentin

正是本着这种精神,我正在写一篇关于 nikita popov 12 年前已经做过的同一主题的文章(如果您正在阅读他的文章,您可以在这里停止阅读)。

毛茸茸的到底是什么?

php 执行字符串插值,在字符串中搜索变量的使用情况,并将其替换为所使用变量的值:

$juice = "apple";
echo "they drank some $juice juice.";
// will output: they drank some apple juice.

此功能仅限于双引号和定界符中的字符串。使用单引号(或 nowdoc)会产生不同的结果:

$juice = "apple";
echo 'they drank some $juice juice.';
// will output: they drank some $juice juice.

看一下:php 不会搜索该单引号字符串中的变量。所以我们可以开始在任何地方使用单引号。所以人们开始建议这样的改变..

- $juice = "apple";
+ $juice = 'apple';

.. 因为它会更快,并且每次执行该文件都会节省大量 cpu 周期,因为 php 不会在单引号字符串中查找变量(无论如何,在示例中不存在)并且每个人都是很高兴,案件已结。

案件结案了吗?

显然,使用单引号和双引号是有区别的,但为了理解发生了什么,我们需要更深入地挖掘。

尽管 php 是一种解释性语言,但它使用编译步骤,其中某些部分一起运行以获得虚拟机实际可以执行的东西,即操作码。那么我们如何从 php 源代码获取操作码呢?

词法分析器

词法分析器扫描源代码文件并将其分解为标记。可以在 token_get_all() 函数文档中找到该含义的简单示例。

t_open_tag (<?php )
t_echo (echo)
t_whitespace ( )
t_constant_encapsed_string ("")

我们可以在这个 3v4l.org 代码片段中看到它的实际效果并使用它。

解析器

解析器获取这些标记并从中生成抽象语法树。当表示为 json 时,上述示例的 ast 表示如下所示:

{
  "data": [
    {
      "nodetype": "stmt_echo",
      "attributes": {
        "startline": 1,
        "starttokenpos": 1,
        "startfilepos": 6,
        "endline": 1,
        "endtokenpos": 4,
        "endfilepos": 13
      },
      "exprs": [
        {
          "nodetype": "scalar_string",
          "attributes": {
            "startline": 1,
            "starttokenpos": 3,
            "startfilepos": 11,
            "endline": 1,
            "endtokenpos": 3,
            "endfilepos": 12,
            "kind": 2,
            "rawvalue": "\"\""
          },
          "value": ""
        }
      ]
    }
  ]
}

如果你也想玩这个,看看其他代码的 ast 是什么样子,我找到了 ryan chandler 的 https://phpast.com/ 和 https://php-ast-viewer.com/ ,它们都显示了你是一段给定的 php 代码的 ast。

编译器

编译器获取 ast 并创建操作码。操作码是虚拟机执行的内容,如果您进行了设置并启用了它,它也会存储在 opcache 中(我强烈推荐)。

要查看操作码,我们有多个选项(也许更多,但我确实知道这三个):

  1. 使用 vulcan 逻辑转储器扩展。它也被纳入 3v4l.org
  2. 使用 phpdbg -p script.php 转储操作码
  3. 或者使用 opcache 的 opcache.opt_debug_level ini 设置使其打印出操作码
    • 0x10000 的值输出优化前的操作码
    • 0x20000 的值输出优化后的操作码
$ echo '<?php echo "";' > foo.php
$ php -dopcache.opt_debug_level=0x10000 foo.php
$_main:
...
0000 echo string("")
0001 return int(1)

假设

回到使用单引号与双引号时节省 cpu 周期的最初想法,我想我们都同意,只有当 php 在运行时为每个请求评估这些字符串时,这才是正确的。

运行时会发生什么?

所以让我们看看 php 为两个不同版本创建了哪些操作码。

双引号:

<?php echo "apple";
0000 echo string("apple")
0001 return int(1)

对比单引号:

<?php echo 'apple';
0000 echo string("apple")
0001 return int(1)

嘿等等,奇怪的事情发生了。这看起来一模一样!我的微优化去哪儿了?

好吧,也许 echo 操作码处理程序的实现会解析给定的字符串,尽管没有标记或其他东西告诉它这样做......嗯?

让我们尝试不同的方法,看看词法分析器对这两种情况做了什么:

营销型企业网站源码响应式界面1.0.1
营销型企业网站源码响应式界面1.0.1

这几年企业营销型网站成为PC端风靡一时的设计主流,主要特点就是首页长度比较长,首页展示的内容量非常大,通过对首页的大量渲染,突出企业优势、产品服务优势等众多信息,让用户在页面停留时间更久,对企业的映像更加深刻,从而达到营销的目的。但是对于大部分的营销型网站来说,一个最大的弱点就是在手机上的用户体验都比较差,而这又恰好是自适应网站所具备的优势,自适应网站能够自动检测访问者浏览设备的分辨率,从而根据访

下载

双引号:

t_open_tag (<?php )
t_echo (echo)
t_whitespace ( )
t_constant_encapsed_string ("")

对比单引号:

line 1: t_open_tag (<?php )
line 1: t_echo (echo)
line 1: t_whitespace ( )
line 1: t_constant_encapsed_string ('')

标记仍然区分双引号和单引号,但检查 ast 将为我们提供两种情况相同的结果 - 唯一的区别是 scalar_string 节点属性中的 rawvalue,它仍然具有单/双引号,但值在这两种情况下都使用双引号。

新假设

难道字符串插值实际上是在编译时完成的吗?

让我们看一个稍微“复杂”的例子:

<?php
$juice="apple";
echo "juice: $juice";

此文件​​的令牌是:

t_open_tag (<?php)
t_variable ($juice)
t_constant_encapsed_string ("apple")
t_whitespace ()
t_echo (echo)
t_whitespace ( )
t_encapsed_and_whitespace (juice: )
t_variable ($juice)

看看最后两个标记!字符串插值是在词法分析器中处理的,因此是编译时的事情,与运行时无关。

双引号是否过多,这就是问题所在!

为了完整起见,让我们看一下由此生成的操作码(优化后,使用 0x20000):

0000 assign cv0($juice) string("apple")
0001 t2 = fast_concat string("juice: ") cv0($juice)
0002 echo t2
0003 return int(1)

这与我们简单的

进入正题:我应该连接还是插值?

让我们看看这三个不同的版本:

<?php
$juice = "apple";
echo "juice: $juice $juice";
echo "juice: ", $juice, " ", $juice;
echo "juice: ".$juice." ".$juice;
  • 第一个版本使用字符串插值
  • 第二个是使用逗号分隔(据我所知,它仅适用于 echo 而不是分配变量或其他任何东西)
  • 第三个选项使用字符串连接

第一个操作码将字符串“apple”分配给变量 $juice:

0000 assign cv0($juice) string("apple")

第一个版本(字符串插值)使用绳索作为底层数据结构,经过优化以尽可能少地复制字符串。

0001 t2 = rope_init 4 string("juice: ")
0002 t2 = rope_add 1 t2 cv0($juice)
0003 t2 = rope_add 2 t2 string(" ")
0004 t1 = rope_end 3 t2 cv0($juice)
0005 echo t1

第二个版本是最有效的内存,因为它不创建中间字符串表示。相反,它会对 echo 进行多次调用,从 i/o 角度来看,这是一个阻塞调用,因此根据您的用例,这可能是一个缺点。

0006 echo string("juice: ")
0007 echo cv0($juice)
0008 echo string(" ")
0009 echo cv0($juice)

第三个版本使用 concat/fast_concat 创建中间字符串表示形式,因此可能比绳索版本使用更多的内存。

0010 T1 = CONCAT string("juice: ") CV0($juice)
0011 T2 = FAST_CONCAT T1 string(" ")
0012 T1 = CONCAT T2 CV0($juice)
0013 ECHO T1

那么……这里正确的做法是什么?为什么是字符串插值?

字符串插值在 echo "juice: $juice" 的情况下使用 fast_concat;或在 echo "juice: $juice $juice"; 的情况下高度优化的 rope_* 操作码;但最重要的是它清楚地传达了意图,并且这些都不是我迄今为止使用过的任何 php 应用程序的瓶颈,所以这些实际上都不重要。

总长dr

字符串插值是编译时的事情。诚然,如果没有 opcache,词法分析器将必须在每个请求上检查双引号字符串中使用的变量,即使没有任何变量,也会浪费 cpu 周期,但说实话:问题不是双引号字符串,而是不使用 opcache!

但是,有一个警告:php 高达 4(我相信甚至包括 5.0,甚至可能是 5.1,我不知道)在运行时进行字符串插值,所以使用这些版本......嗯,我想如果有人真的仍然使用 php 5,与上面相同:问题不是双引号字符串,而是使用过时的 php 版本。

最终建议

更新到最新的php版本,启用opcache,从此幸福快乐地生活!

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

455

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

546

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

335

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

82

2025.09.10

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

760

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

221

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1566

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

649

2023.11.24

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

76

2026.03.11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号