[Translation] understand the definition of PHP internal functions (for PHP developers' PHP source code-Part 2) and developer source code. [Translation] understand the definition of PHP internal functions (for PHP developers' PHP source code-Part 2). The developer source code is from: www. aintnot. understanding the definition of PHP internal functions (for PHP developers PHP source code-the second part), developer source code
Article from: http://www.aintnot.com/2016/02/10/understanding-phps-internal-function-definitions-ch
Original article: https://nikic.github.io/2012/03/16/Understanding-PHPs-internal-function-definitions.html
Welcome to the second part of the "PHP source code for PHP developers" series.
In the previous article, ircmaxell explains where you can find the PHP source code, its basic directory structure, and briefly introduced some C languages (because PHP is written in C ). If you miss the article, you may need to read it before you start reading it.
In this article, we are talking about locating the definition of PHP internal functions and understanding their principles.
How to find the function definition
In the beginning, let's try to find out the strpos function definition.
Step 1: go to the PHP 5.4 Root Directory and enter strpos in the search box at the top of the page. The search result is a large list, showingstrposThe location where the PHP source code appears.
Because this result is not very helpful to us, we use a small trick: we search for "PHP_FUNCTION strpos" (do not miss double quotation marks, they are very important), insteadstrpos.
Now we get two entry links:
/PHP_5_4/ext/standard/
php_string.h 48 PHP_FUNCTION(strpos);
string.c 1789 PHP_FUNCTION(strpos)
The first thing to note is that both locations areext/standardFolder. This is what we want to find, because the strpos function (like most string, array, and file functions) is part of the standard extension.
Now, open two links on the new tab and see what code is hidden behind them.
You will see that the first link takes you to the php_string.h file, which contains the following code:
// ... PHP_FUNCTION(strpos); PHP_FUNCTION(stripos); PHP_FUNCTION(strrpos); PHP_FUNCTION(strripos); PHP_FUNCTION(strrchr); PHP_FUNCTION(substr); // ...
This is a typical header file (a file ending with the. h suffix): a simple function list, which is defined elsewhere. In fact, we are not interested in this because we already know what we are looking.
The second link is more interesting: it takes usstring.cFile, which contains the real source code of the function.
Before I take you through this function step by step, I recommend that you try to understand it yourself. This is a very simple function. although you don't know the real details, most code looks very clear.
Skeleton of PHP functions
All PHP functions use the same basic structure. Define variables at the top of the function, and then callzend_parse_parametersFunction, and then to the main logic, which includesRETURN_***Andphp_error_docref.
Let's start with the function definition:
zval *needle;char *haystack;char *found = NULL;char needle_char[2];long offset = 0;int haystack_len;
The first line defines a pointzvalPointerneedle. Zval represents the definition of any PHP variable in PHP. What is it like? I will focus on it in the next article.
The second row defines the pointer to a single characterhaystack. At this time, you need to remember that in the C language, arrays represent pointers pointing to their first element. For example,haystackThe variable points to$haystackThe first character of the string variable.haystack + 1Will point to the second character,haystack + 2Point to the third, and so on. Therefore, you can read the entire string by incrementing the pointer one by one.
The problem is that PHP needs to know where the string ends. Otherwise, it will increment the pointer rather than stop. To solve this problem, PHP also saves a clear length, which ishaystack_lenVariable.
Now, in the above definition, we are interested in the offset variable, which is used to save the third parameter of the function: start the search offset. It is defined using long. like int, it is also an integer data type. The difference between the two is not important, but you need to know that in PHP, integer values are stored using long, and string lengths are stored using int.
Now let's take a look at the following three lines:
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &haystack, &haystack_len, &needle, &offset) == FAILURE) { return;}
The three lines of code are used to obtain the parameters passed to the function and store them in the variables declared above.
The first parameter passed to the function is the number of parameters passed. This number is passedZEND_NUM_ARGS()Macro.
The next function isTSRMLS_CCMacro, which is a feature of PHP. You will find this strange macro scattered in many places in the PHP code library. Is part of thread security Resource Manager (TSRM), which ensures that PHP will not confuse variables between multiple threads. This is not very important for us. when you seeTSRMLS_CC(OrTSRMLS_DC), Ignore it. (There is a strange thing you should note that there is no comma before "argument. This is because whether or not you use the thread-safe function to create a function, the macro will be interpreted as null or trsm_ls. Therefore, comma is a part of the macro .)
Now we come to the important thing: the "sz \ | l" string marks the parameters received by the function. :
S // The first parameter is the string z // The second parameter is a zval struct, any variable | // identifies the following parameter as optional l // The third parameter is the long type (integer)
In addition to s, z, and l, there are more identification types, but most of them can be clearly defined in characters. For example, B is boolean, d is double (floating-point number), a is array, f is callback (function), and o is object.
Parameters&haystack,&haystack_len,&needle,&offsetSpecifies the variable of the parameter to be assigned a value. As you can see, they are all transmitted using references (&), meaning that they are not passing the variables themselves, but pointing to their pointers.
After this function is called,haystackIt will contain the haystack string,haystack_lenIs the length of the string, needle is the value of needle, and offset is the starting offset.
In addition, this function uses FAILURE (when you try to pass invalid parameters to the function, for example, passing an array value to a string) to check. In this casezend_parse_parametersThe function will throw a warning, and this function will return immediately (null will be returned to the PHP user-Layer Code ).
After parameter resolution, the main function body starts:
if (offset < 0 || offset > haystack_len) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset not contained in string"); RETURN_FALSE;}
What this code does is obvious. if the offset exceeds the boundary, an E_WARNING-level error will be thrown through the php_error_docref function, and then the function uses the RETURN_FALSE macro to return false.
php_error_docrefIs an error function. you can find it in the extended Directory (for example, ext folder ). Its name is defined based on the Reference Document returned on the error page (that is, functions that do not work normally. There is anotherzend_errorFunction, which is mainly used by Zend Engine, but often appears in the extended code.
Both functions use the sprintf function, such as formatting information. Therefore, the error message can contain placeholders that will be filled by subsequent parameters. The following is an example:
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to write %d bytes to %s", Z_STRLEN_PP(tmp), filename);// %d is filled with Z_STRLEN_PP(tmp)// %s is filled with filename
Let's continue to parse the code:
if (Z_TYPE_P(needle) == IS_STRING) { if (!Z_STRLEN_P(needle)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter"); RETURN_FALSE; } found = php_memnstr(haystack + offset, Z_STRVAL_P(needle), Z_STRLEN_P(needle), haystack + haystack_len);}
The first five lines are very clear: this branch will only be executed when needle is a string and will throw an error if it is null. Then it comes to an interesting part:php_memnstrCalled. This function does the main work. As usual, you can click the function name and view its source code.
php_memnstrReturns the pointer to the position of needle at the first occurrence of haystack (that is why the found variable is defined as char *, for example, the pointer to a character ). Here, we can know that offset can be calculated by subtraction, which can be seen at the end of the function:
RETURN_LONG(found - haystack);
Finally, let's take a look at the branches when needle is used as a non-string:
else { if (php_needle_char(needle, needle_char TSRMLS_CC) != SUCCESS) { RETURN_FALSE; } needle_char[1] = 0; found = php_memnstr(haystack + offset, needle_char, 1, haystack + haystack_len);}
I only reference what I wrote in the manual: "If needle is not a string, it will be converted to an integer and considered a sequential value. "This basically means that apart from writingstrpos($str, 'A')You can also writestrpos($str, 65)Because the character is encoded as 65.
If you look at the variable definition, you can seeneedle_charIs definedchar needle_char[2]That is, there are two character strings,php_needle_charThe true character ('A' here) is converted to needle_char [0]. Then, the strpos function sets needle_char [1] to 0. The reason is that in C, the string ends with '\ 0', that is, the last character is set to NUL (the character encoded as 0 ). In the PHP syntax environment, this condition does not exist because PHP stores the length of all strings (so it does not need 0 to help find the end of the string ), however, to ensure compatibility with C functions, it is implemented in PHP.
Zend functions
I am tired of the strpos function. let's find another function: strlen. We use the following method:
Search for strlen from the PHP5.4 source code root directory.
You will see the use of a bunch of irrelevant functions, so search for "PHP_FUNCTION strlen ". When you search this way, you will find something strange: no results.
The reason is that strlen is a minority of functions defined through Zend Engine instead of PHP extension. In this case, the function is not usedPHP_FUNCTION(strlen)Definition,ZEND_FUNCTION(strlen). Therefore, we also need to search for "ZEND_FUNCTION strlen ".
We all know that we need to click the link without a semicolon to jump to the definition of the source code. This link takes us to the following function definition:
ZEND_FUNCTION(strlen){ char *s1; int s1_len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &s1, &s1_len) == FAILURE) { return; } RETVAL_LONG(s1_len);}
This function is too simple to implement. I don't think I need further explanation.
Method
We will talk about more details about how classes and objects work in other articles, but as a little spoiler: you can search in the search boxClassName::methodNameTo search for object methods. For example, try to searchSplFixedArray::getSize.
Next part
The next part will be published again. It will talk about what zval is, how they work, and how they are used in the source code (all Z _*Macro ).
Understand the definition of PHP internal functions (for PHP developers PHP source code-the second part), the developer Source Code Article from: http://www.aintnot.com/2016/02/10/understanding-phps-internal-fu...