search
HomeBackend DevelopmentPHP Tutorial[译] 理解PHP内部函数的定义(给PHP开发者的PHP源码-第二部分),开发者源码_PHP教程

[译] 理解PHP内部函数的定义(给PHP开发者的PHP源码-第二部分),开发者源码

<p>文章来自:http://www.aintnot.com/2016/02/10/understanding-phps-internal-function-definitions-ch</p>
<p>原文:https://nikic.github.io/2012/03/16/Understanding-PHPs-internal-function-definitions.html</p>

欢迎来到"给PHP开发者的PHP源码"系列的第二部分。

在上一篇中,ircmaxell说明了你可以在哪里找到PHP的源码,它的基本目录结构以及简单地介绍了一些C语言(因为PHP是用C语言来写的)。如果你错过了那篇文章,在你开始读这篇文章之前也许你应该读一下它。

在这篇文章中,我们谈论的是定位PHP内部函数的定义,以及理解它们的原理。

如何找到函数的定义

作为开始,让我们尝试找出strpos函数的定义。

尝试的第一步,就是去PHP 5.4根目录然后在页面顶部的搜索框输入strpos。搜索的结果是一个很大的列表,展示了strpos在PHP源码中出现的位置。

 

因为这个结果对我们并没有太大的帮助,我们使用一个小技巧:我们搜索"PHP_FUNCTION strpos"(不要漏了双引号,它们很重要),而不是strpos.

现在我们得到两个入口链接:

<span class="hljs-regexp">/PHP_5_4/ext/standard/</span> <span class="hljs-regexp">  php_string.h <span class="hljs-number">48 PHP_FUNCTION(strpos);</span></span> <span class="hljs-regexp"><span class="hljs-number">  string.c <span class="hljs-number">1789 PHP_FUNCTION(strpos) </span></span></span>

第一个要注意的事情是,两个位置都是在ext/standard文件夹。这就是我们希望找到的,因为strpos函数(跟大部分string,array和文件函数一样)是standard扩展的一部分。

现在,在新标签页打开两个链接,然后看看它们背后藏了什么代码。

你会看到第一个链接带你到了php_string.h文件,它包含了下面的代码:

<code>   
       <span>//</span><span> ...</span>
<span>  PHP_FUNCTION(strpos);
  PHP_FUNCTION(stripos);
  PHP_FUNCTION(strrpos);
  PHP_FUNCTION(strripos);
  PHP_FUNCTION(strrchr);
  PHP_FUNCTION(substr);
  </span><span>//</span><span> ...</span>

 

这就是一个典型的头文件(以.h后缀结尾的文件)的样子:单纯的函数列表,函数在其他地方定义。事实上,我们对这些并不感兴趣,因为我们已经知道我们要找的是什么。

第二个链接更有趣:它带我们到string.c文件,这个文件包含了函数真正的源代码。

在我带你一步一步地查阅这个函数之前,我推荐你自己尝试理解这个函数。这是一个很简单的函数,尽管你不知道真正的细节,但大多数代码看起来都很清晰。

PHP函数的骨架

所有的PHP函数都使用同一个基本结构。在函数顶部定义了各个变量,然后调用zend_parse_parameters函数,然后到了主要的逻辑,当中有RETURN_***php_error_docref的调用。

那么,让我们以函数的定义来开始:

zval *<span>needle;
char </span>*<span>haystack;
char </span>*found = <span>NULL</span><span>;
char  needle_char[</span>2<span>];
long  offset </span>= 0<span>;
int   haystack_len;</span>
<span class="hljs-title"><br></span>  

第一行定义了一个指向zval的指针needle。zval是在PHP内部代表任意一个PHP变量的定义。它真正是怎么样的会在下一篇文章重点谈论。

第二行定义了指向单个字符的指针haystack。这时候,你需要记住,在C语言里面,数组代表指向它们第一个元素的指针。比如说,haystack变量会指向你所传递的$haystack字符串变量的第一个字符。haystack + 1会指向第二个字符,haystack + 2指向第三个,以此类推。因此,通过逐个递增指针,可以读取整个字符串。

那么问题来了,PHP需要知道字符串在哪里结束。不然的话,它会一直递增指针而不会停止。为了解决这个问题,PHP也保存了明确的长度,这就是haystack_len变量。

现在,在上面的定义中,我们感兴趣的是offset变量,这个变量用来保存函数的第三个参数:开始搜索的偏移量。它使用long来定义,跟int一样,也是整型数据类型。现在这两者的差异并不重要,但你需要知道的是在PHP中,整型值使用long来存储,字符串的长度使用int来存储。

现在来看看下面的三行:

<span>if</span> (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, <span>"</span><span>sz|l</span><span>"</span>, &haystack, &haystack_len, &needle, &offset) ==<span> FAILURE) {
    </span><span>return</span><span>;
}</span>
<span class="hljs-keyword"><br></span>

这三行代码做的事情就是,获取传递到函数的参数,然后把它们存储到上面声明的变量中。

传递给函数的第一个参数是传递参数的数量。这个数字通过ZEND_NUM_ARGS()宏提供。

下一个函数是TSRMLS_CC宏,这是PHP的一种特性。你会发现这个奇怪的宏分散在PHP代码库的很多地方。是线程安全资源管理器(TSRM)的一部分,它保证PHP不会在多线程之间混乱变量。这对我们来说不是很重要,当你在代码中看到TSRMLS_CC(或者TSRMLS_DC)的时候,忽略它就行。(有一个奇怪的地方你需要注意的是,在"argument"之前没有逗号。这是因为不管你是否使用线程安全创建函数,该宏会被解释为空或者, trsm_ls。因此,逗号是宏的一部分。)

现在,我们来到重要的东西:"sz\|l"字符串标记了函数接收的参数。:

s  <span>//</span><span> 第一个参数是字符串</span>
z  <span>//</span><span> 第二个参数是一个zval结构体,任意的变量</span>
|  <span>//</span><span> 标识接下来的参数是可选的</span>
l  <span>//</span><span> 第三个参数是long类型(整型)</span>

除了s,z,l之外,还有更多的标识类型,但是大部分都能从字符中清楚其意思。例如b是boolean,d是double(浮点型数字),a是array,f是回调(function),o是object。

接下来的参数&haystack&haystack_len&needle&offset指定了需要赋值的参数的变量。你可以看到,它们都是使用引用(&)传递的,意味着它们传递的不是变量本身,而是指向它们的指针。

这个函数调用之后,haystack会包含haystack字符串,haystack_len是字符串的长度,needle是needle的值,offset是开始的偏移量。

而且,这个函数使用FAILURE(当你尝试传递无效参数到函数时会发生,比如传递一个数组赋值到字符串)来检查。这种情况下zend_parse_parameters函数会抛出警告,而此函数马上返回(会返回null给PHP的用户层代码)。

在参数解析完毕以后,主函数体开始:

<span>if</span> (offset < <span>0</span> || offset ><span> haystack_len) {
    php_error_docref(NULL TSRMLS_CC, E_WARNING, </span><span>"</span><span>Offset not contained in string</span><span>"</span><span>);
    RETURN_FALSE;
}</span>
<span class="hljs-keyword"><br></span>

这段代码做的事情很明显,如果offset超出了边界,一个E_WARNING级别的错误会通过php_error_docref函数抛出,然后函数使用RETURN_FALSE宏返回false。

php_error_docref是一个错误函数,你可以在扩展目录找到它(比如,ext文件夹)。它的名字根据它在错误页面中返回文档参考(就是那些不会正常工作的函数)定义。还有一个zend_error函数,它主要被Zend Engine使用,但也经常出现在扩展代码中。

两个函数都使用sprintf函数,比如格式化信息,因此错误信息可以包含占位符,那些占位符会被后面的参数填充。下面有一个例子:

php_error_docref(NULL TSRMLS_CC, E_WARNING, <span>"</span><span>Failed to write %d bytes to %s</span><span>"</span><span>, Z_STRLEN_PP(tmp), filename);
</span><span>//</span><span> %d is filled with Z_STRLEN_PP(tmp)
</span><span>//</span><span> %s is filled with filename</span>

让我们继续解析代码:

<span>if</span> (Z_TYPE_P(needle) ==<span> IS_STRING) {
    </span><span>if</span> (!<span>Z_STRLEN_P(needle)) {
        php_error_docref(NULL TSRMLS_CC, E_WARNING, </span><span>"</span><span>Empty delimiter</span><span>"</span><span>);
        RETURN_FALSE;
    }

    found </span>= php_memnstr(haystack +<span> offset,
                        Z_STRVAL_P(needle),
                        Z_STRLEN_P(needle),
                        haystack </span>+<span> haystack_len);
}</span>
<span class="hljs-keyword"><br></span>

前面的5行非常清晰:这个分支只会在needle为字符串的情况下执行,而且如果它是空的话会抛出错误。然后到了比较有趣的一部分:php_memnstr被调用了,这个函数做了主要的工作。跟往常一样,你可以点击该函数名然后查看它的源码。

php_memnstr返回指向needle在haystack第一次出现的位置的指针(这就是为什么found变量要定义为char *,例如,指向字符的指针)。从这里可以知道,偏移量(offset)可以通过减法被简单地计算,可以在函数的最后看到:

RETURN_LONG(found - haystack);

最后,让我们来看看当needle作为非字符串的时候的分支:

<span>else</span><span> {
    </span><span>if</span> (php_needle_char(needle, needle_char TSRMLS_CC) !=<span> SUCCESS) {
        RETURN_FALSE;
    }
    needle_char[</span><span>1</span>] = <span>0</span><span>;

    found </span>= php_memnstr(haystack +<span> offset,
                        needle_char,
                        </span><span>1</span><span>,
                        haystack </span>+<span> haystack_len);
}</span>
<span class="hljs-keyword"><br></span>

我只引用在手册上写的"如果 needle 不是一个字符串,那么它将被转换为整型并被视为字符顺序值。"这基本上说明,除了写strpos($str, 'A'),你还可以写strpos($str, 65),因为A字符的编码是65。

如果你再查看变量定义,你可以看到needle_char被定义为char needle_char[2],即有两个字符的字符串,php_needle_char会将真正的字符(在这里是'A')到needle_char[0]。然后strpos函数会设置needle_char[1]为0。这背后的原因是因为,在C里面,字符串是使用'\0'结尾,就是说,最后一个字符被设置为NUL(编码为0的字符)。在PHP的语法环境里,这样的情况不存在,因为PHP存储了所有字符串的长度(因此它不需要0来帮助找到字符串的结尾),但是为了保证与C函数的兼容性,还是在PHP的内部实现了。

Zend functions

我对strpos这个函数感觉好累,让我们找另一个函数吧:strlen。我们使用之前的方法:

从PHP5.4源码根目录开始搜索strlen。

你会看到一堆无关的函数的使用,因此,搜索“PHP_FUNCTION strlen”。当你这么搜索的时候,你会发现一些奇怪的事情发生了:没有任何的结果。

原因是,strlen是少数通过Zend Engine而不是PHP扩展定义的函数。这种情况下,函数不是使用PHP_FUNCTION(strlen)定义,而是ZEND_FUNCTION(strlen)。因此,我们也要搜索“ZEND_FUNCTION strlen”。

我们都知道,我们需要点击没有分号结尾的链接跳到源码的定义。这个链接带我们到下面的函数定义:

<span>ZEND_FUNCTION(strlen)
{
    </span><span>char</span> *<span>s1;
    </span><span>int</span><span> s1_len;

    </span><span>if</span> (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, <span>"</span><span>s</span><span>"</span>, &s1, &s1_len) ==<span> FAILURE) {
        </span><span>return</span><span>;
    }

    RETVAL_LONG(s1_len);
}</span>

这个函数实现太简单了,我不觉得我还需要进一步的解释。

方法

我们会谈论类和对象如何工作的更多细节在其他文章里,但作为一个小小的剧透:你可以通过在搜索框搜索ClassName::methodName来搜索对象方法。例如,尝试搜索SplFixedArray::getSize

下一部分

下一部分会再次发表在。会谈论到zval是什么,它们是怎么工作的,以及它们是怎么在源码中被使用的(所有的Z_*宏)。

www.bkjia.comtruehttp://www.bkjia.com/PHPjc/1099830.htmlTechArticle[译] 理解PHP内部函数的定义(给PHP开发者的PHP源码-第二部分),开发者源码 文章来自:http://www.aintnot.com/2016/02/10/understanding-phps-internal-fu...
Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
PHP's Purpose: Building Dynamic WebsitesPHP's Purpose: Building Dynamic WebsitesApr 15, 2025 am 12:18 AM

PHP is used to build dynamic websites, and its core functions include: 1. Generate dynamic content and generate web pages in real time by connecting with the database; 2. Process user interaction and form submissions, verify inputs and respond to operations; 3. Manage sessions and user authentication to provide a personalized experience; 4. Optimize performance and follow best practices to improve website efficiency and security.

PHP: Handling Databases and Server-Side LogicPHP: Handling Databases and Server-Side LogicApr 15, 2025 am 12:15 AM

PHP uses MySQLi and PDO extensions to interact in database operations and server-side logic processing, and processes server-side logic through functions such as session management. 1) Use MySQLi or PDO to connect to the database and execute SQL queries. 2) Handle HTTP requests and user status through session management and other functions. 3) Use transactions to ensure the atomicity of database operations. 4) Prevent SQL injection, use exception handling and closing connections for debugging. 5) Optimize performance through indexing and cache, write highly readable code and perform error handling.

How do you prevent SQL Injection in PHP? (Prepared statements, PDO)How do you prevent SQL Injection in PHP? (Prepared statements, PDO)Apr 15, 2025 am 12:15 AM

Using preprocessing statements and PDO in PHP can effectively prevent SQL injection attacks. 1) Use PDO to connect to the database and set the error mode. 2) Create preprocessing statements through the prepare method and pass data using placeholders and execute methods. 3) Process query results and ensure the security and performance of the code.

PHP and Python: Code Examples and ComparisonPHP and Python: Code Examples and ComparisonApr 15, 2025 am 12:07 AM

PHP and Python have their own advantages and disadvantages, and the choice depends on project needs and personal preferences. 1.PHP is suitable for rapid development and maintenance of large-scale web applications. 2. Python dominates the field of data science and machine learning.

PHP in Action: Real-World Examples and ApplicationsPHP in Action: Real-World Examples and ApplicationsApr 14, 2025 am 12:19 AM

PHP is widely used in e-commerce, content management systems and API development. 1) E-commerce: used for shopping cart function and payment processing. 2) Content management system: used for dynamic content generation and user management. 3) API development: used for RESTful API development and API security. Through performance optimization and best practices, the efficiency and maintainability of PHP applications are improved.

PHP: Creating Interactive Web Content with EasePHP: Creating Interactive Web Content with EaseApr 14, 2025 am 12:15 AM

PHP makes it easy to create interactive web content. 1) Dynamically generate content by embedding HTML and display it in real time based on user input or database data. 2) Process form submission and generate dynamic output to ensure that htmlspecialchars is used to prevent XSS. 3) Use MySQL to create a user registration system, and use password_hash and preprocessing statements to enhance security. Mastering these techniques will improve the efficiency of web development.

PHP and Python: Comparing Two Popular Programming LanguagesPHP and Python: Comparing Two Popular Programming LanguagesApr 14, 2025 am 12:13 AM

PHP and Python each have their own advantages, and choose according to project requirements. 1.PHP is suitable for web development, especially for rapid development and maintenance of websites. 2. Python is suitable for data science, machine learning and artificial intelligence, with concise syntax and suitable for beginners.

The Enduring Relevance of PHP: Is It Still Alive?The Enduring Relevance of PHP: Is It Still Alive?Apr 14, 2025 am 12:12 AM

PHP is still dynamic and still occupies an important position in the field of modern programming. 1) PHP's simplicity and powerful community support make it widely used in web development; 2) Its flexibility and stability make it outstanding in handling web forms, database operations and file processing; 3) PHP is constantly evolving and optimizing, suitable for beginners and experienced developers.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
4 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
4 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
4 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: How To Unlock Everything In MyRise
1 months agoBy尊渡假赌尊渡假赌尊渡假赌

Hot Tools

PhpStorm Mac version

PhpStorm Mac version

The latest (2018.2.1) professional PHP integrated development tool

SublimeText3 English version

SublimeText3 English version

Recommended: Win version, supports code prompts!

WebStorm Mac version

WebStorm Mac version

Useful JavaScript development tools

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

Integrate Eclipse with SAP NetWeaver application server.

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment