PHP中strlen()函数的源代码在哪里?

4
我在查看 php-src/Zend/zend_API.c 时,并没有找到 PHP 中 strlen() 函数的源代码,在整个代码库中搜索并不会有太多帮助,因为 libc strlen 函数随处可见。谷歌搜索也没什么用。
我尝试使用 Vulcan Logic Dumper 扩展来检查底层发生了什么。
我试着使用以下代码进行测试:
<?php

strlen("foo"); strpos("foo", "f");

我得到的内容如下:

查找入口点
从位置0开始分析分支
发现1个跳转。 (Code = 62) 位置1 = -2
文件名:/ tmp / test.php
函数名称:(null)
操作数数量:7
编译变量:none
行#*EIO op fetch ext return operands
-------------------------------------------------- -----------------------------------
3 0 E > ECHO 3
4 1 INIT_FCALL 'strpos'
2 SEND_VAL 'foo'
3 SEND_VAL 'o'
4 DO_ICALL $0
5 ECHO $0
6 > RETURN 1

注意strpos()显示为函数调用,但strlen()没有显示。所以我在 PHP 7.4 上进行了一个实验,并得到了一些有趣的结果。

代码

<?php
$str = "foo";

echo strlen($str);
echo strpos($str, "o");

Vulcan的输出

查找入口点
从位置0开始分析分支
发现1个跳转 (代码=62),位置1=-2
文件名:/tmp/test2.php
函数名:(null)
操作数:9
已编译变量:!0=$str
行号     #* E I O 操作                             获取                扩展   返回值  操作数
-------------------------------------------------------------------------------------
   2     0  E >   ASSIGN                                                    !0, 'foo'
   4     1        STRLEN                                            ~2      !0
         2        ECHO                                                      ~2
   5     3        INIT_FCALL                                               'strpos'
         4        SEND_VAR                                                  !0
         5        SEND_VAL                                                  'o'
         6        DO_ICALL                                          $3      
         7        ECHO                                                      $3
         8      > RETURN                                                    1

注意,STRLEN 突然出现在操作列表中,但是奇怪的是,strpos() 函数以 INIT_FCALL 的形式出现。看起来 strlen() 和其他函数不同。我尝试查阅官方手册以更好地了解操作码的工作方式,但没能找到太有用的信息。


有没有人可以解释一下为什么 strlen() 表现得如此不同于其他函数,并可能指向它的源代码?也许我找不到它的原因与它如此特殊有关?我不确定。


2
Sherif已经给出了一个非常好的回答。简而言之:1)PHP的strlen()在内部映射到ZSTR_LEN(),2)您可以在此处找到PHP strpos()的源代码:https://github.com/php/php-src/blob/master/ext/standard/string.c - FoggyDay
1个回答

6

strlen() 实际上是 PHP 7 中的一个操作码,因此它的行为与典型的函数不同。 它的源代码位于php-src/Zend/zend_string.h第53行(截至本文撰写时),这被定义为一个宏。

#define ZSTR_LEN(zstr)  (zstr)->len

基本上只是读取_zend_string结构体的len成员,该成员将字符串的长度存储为成员变量。

如果你查看git-blame,你会发现这个宏大约是在2015年PHP 7发布时添加的。

这是提交记录:https://github.com/php/php-src/commit/4bd22cf1c1d6a262fe2f026e082f2565433c53df

这是我的git日志:

commit 4bd22cf1c1d6a262fe2f026e082f2565433c53df
Author: Dmitry Stogov 
Date:   Mon Jun 29 16:44:54 2015 +0300
Improved zend_string API (Francois Laupretre)
Squashed commit of the following:
commit d96eab8d79b75ac83d49d49ae4665f948d15a804 Author: Francois Laupretre Date: Fri Jun 26 01:23:31 2015 +0200
Use the new 'ZSTR' macros in the rest of the code.
Does not change anything to the generated code (thanks to compat macros) but cleaner.
commit b3526439104ac7a89a8e0c79dbebf33b22bd01b8 Author: Francois Laupretre Date: Thu Jun 25 13:45:06 2015 +0200
Improve zend_string API
Add missing methods

因此,看起来在PHP 7发布前后进行了一些API的改进。不清楚这是否意味着strlen()从函数变为操作码,或者它一直是操作码。

我确实看到了内部字符串如何影响您的实验中Vulcan的输出。如果使用内部字符串,PHP似乎以某种方式在执行器中采取了某种快捷方式。我不清楚具体情况,但是它似乎确实与典型函数的行为有所不同。


谢谢!你不会相信我花了多少个小时挖掘这个源代码,试图弄清楚strlen是如何工作的,哈哈。你真是一个巫师! - emptyheap
没问题!PHP的源代码有时确实会让人感到困惑。 - Sherif

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接