问题
I was looking through php-src/Zend/zend_API.c and couldn't find the source code for the strlen()
function in PHP anywhere. Grepping through the code base didn't really help as it's littered with libc strlen
everywhere. Googling doesn't much help either.
I tried using the Vulcan Logic Dumper extension to inspect what's going on under the hood.
I tried the following code as a test:
<?php
strlen("foo"); strpos("foo", "f");
This is what I got:
Finding entry points Branch analysis from position: 0 1 jumps found. (Code = 62) Position 1 = -2 filename: /tmp/test.php function name: (null) number of ops: 7 compiled vars: none line #* E I O 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
Notice how strpos()
shows up as a function call, but not strlen()
. So I tried this (this on PHP 7.4, by the way) as an experiment and got something interesting.
Code
<?php
$str = "foo";
echo strlen($str);
echo strpos($str, "o");
Output from Vulcan
Finding entry points Branch analysis from position: 0 1 jumps found. (Code = 62) Position 1 = -2 filename: /tmp/test2.php function name: (null) number of ops: 9 compiled vars: !0 = $str line #* E I O op fetch ext return operands ------------------------------------------------------------------------------------- 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
Notice how all of a sudden STRLEN
shows up in the op list, but strangely enough strpos()
shows up as INIT_FCALL
. Seems like something's different about strlen()
than other functions. I tried looking through the manual to better understand how the opcodes work, but hit a dead end as not much useful information is there.
Can anyone explain why strlen()
seems to behave so different than other functions and perhaps point me to the source code for it? Perhaps the reason I cannot seem to find its source might have something to do with why it's so special? I'm not sure.
回答1:
strlen()
is actually an opcode in PHP 7 and thus doesn't behave like a typical function. Its source code is located in php-src/Zend/zend_string.h on line 53 (as of the time of this writing), which is defined as a Macro.
#define ZSTR_LEN(zstr) (zstr)->len
It's basically just reading the len
member of the _zend_string struct, which stores the length of the string as a member.
If you look at the git-blame you'll see that particular macro was added around the time of PHP 7's release in 2015.
Here's the commit: https://github.com/php/php-src/commit/4bd22cf1c1d6a262fe2f026e082f2565433c53df
Here's what my git log says:
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
So it looks like at some point around PHP 7's release some improvements were made to the API. It's unclear if this means strlen()
went from being a function to being an opcode, or if it was always an opcode.
I do see, though, how the interned string stuff might effect the output of Vulcan in your experiment. If you use an interned string PHP seems to take some kind of shortcut in the executor for some reason. I'm unclear as to how, exactly, but yes it does appear to behave somewhat differently from a typical function.
来源:https://stackoverflow.com/questions/60134074/where-is-the-source-code-for-strlen-function-in-php