Heim >Backend-Entwicklung >PHP-Tutorial >So verwenden Sie interne PHP-Funktionen

So verwenden Sie interne PHP-Funktionen

伊谢尔伦
伊谢尔伦Original
2017-06-26 10:24:461485Durchsuche

So finden Sie die Definition einer Funktion

Zunächst versuchen wir, die Definition der strpos-Funktion zu finden.

Der erste Schritt besteht darin, zum PHP 5.4-Stammverzeichnis zu gehen und strpos in das Suchfeld oben auf der Seite einzugeben. Das Ergebnis der Suche ist eine große Liste, die zeigt, wo strpos im PHP-Quellcode vorkommt.

Da dieses Ergebnis für uns nicht sehr hilfreich ist, verwenden wir einen kleinen Trick: Wir suchen nach „PHP_FUNCTION strpos“ (verpassen Sie nicht die doppelten Anführungszeichen, sie sind wichtig) anstelle von strpos.

Jetzt bekommen wir zwei Eintragslinks:

/PHP_5_4/ext/standard/

php_string.h 48 PHP_FUNCTION(strpos);

string.c 1789 PHP_FUNCTION( strpos)

Als Erstes ist zu beachten, dass sich beide Speicherorte im ext/standard-Ordner befinden. Dies ist es, was wir erwarten, da die strpos-Funktion (wie die meisten String-, Array- und Dateifunktionen) Teil der Standarderweiterung ist.

Öffnen Sie nun beide Links in einem neuen Tab und sehen Sie, welcher Code sich dahinter verbirgt.

Sie werden sehen, dass der erste Link Sie zur Datei php_string.h führt, die den folgenden Code enthält:

// ...
PHP_FUNCTION(strpos);
PHP_FUNCTION(stripos);
PHP_FUNCTION(strrpos);
PHP_FUNCTION(strripos);
PHP_FUNCTION(strrchr);
PHP_FUNCTION(substr);
// ...

Dies ist eine typische Header-Datei (mit einem .h-Suffix) Datei am Ende) sieht aus wie eine einfache Liste von Funktionen, die Funktionen sind an anderer Stelle definiert. Tatsächlich interessiert uns das alles nicht, weil wir bereits wissen, wonach wir suchen.

Der zweite Link ist interessanter: Er führt uns zur Datei string.c, die den eigentlichen Quellcode der Funktion enthält.

Bevor ich Sie Schritt für Schritt durch diese Funktion führe, empfehle ich Ihnen, zu versuchen, diese Funktion selbst zu verstehen. Es handelt sich um eine sehr einfache Funktion, und obwohl Sie die tatsächlichen Details nicht kennen, sieht der größte Teil des Codes klar aus.

Das Grundgerüst der PHP-Funktion

Alle PHP-Funktionen verwenden die gleiche Grundstruktur. Jede Variable wird oben in der Funktion definiert, dann wird die Funktion zend_parse_parameters aufgerufen und dann kommt die Hauptlogik, einschließlich der Aufrufe von RETURN_*** und php_error_docref.

Also beginnen wir mit der Definition der Funktion:

zval *needle;

char *haystack;

char *found = NULL;

char Needle_char[2];

long offset = 0;

int haystack_len;

Die erste Zeile definiert eine Zeigernadel, die auf zval zeigt. zval ist die Definition, die jede PHP-Variable in PHP darstellt. Wie es wirklich aussieht, erfahren Sie im nächsten Artikel.

Die zweite Zeile definiert haystack, einen Zeiger auf ein einzelnes Zeichen. An dieser Stelle müssen Sie bedenken, dass Arrays in der Sprache C Zeiger auf ihr erstes Element darstellen. Beispielsweise zeigt die Variable haystack auf das erste Zeichen der Variablen $haystackstring, die Sie übergeben haben. Heuhaufen + 1 zeigt auf das zweite Zeichen, Heuhaufen + 2 zeigt auf das dritte Zeichen und so weiter. Durch schrittweises Erhöhen des Zeigers kann also die gesamte Zeichenfolge gelesen werden.

Dann kommt das Problem, PHP muss wissen, wo der String endet. Andernfalls wird der Zeiger weiter erhöht, ohne anzuhalten. Um dieses Problem zu lösen, speichert PHP auch eine explizite Länge, nämlich die Variable haystack_len.

Was uns nun in der obigen Definition interessiert, ist die Offset-Variable, die zum Speichern des dritten Parameters der Funktion verwendet wird: dem Offset zum Starten der Suche. Es wird mit long definiert, das wie int ebenfalls ein Integer-Datentyp ist. Nun ist der Unterschied zwischen den beiden nicht wichtig, aber Sie müssen wissen, dass in PHP ganzzahlige Werte als long und die Länge von Zeichenfolgen als int gespeichert werden.

Sehen Sie sich nun die folgenden drei Zeilen an:

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &haystack, &haystack_len, &needle, &offset) == FAILURE) {
    return;
}

Diese drei Codezeilen bewirken, dass die Parameter an die -Funktion übergeben und dann gespeichert werden sie in die oben deklarierte Variable ein.

Der erste an die Funktion übergebene Parameter ist die Anzahl der übergebenen Parameter. Diese Nummer wird über das Makro ZEND_NUM_ARGS() bereitgestellt.

Die nächste Funktion ist das Makro TSRMLS_CC, eine Funktion von PHP. Sie finden dieses seltsame Makro an vielen Stellen in der PHP-Codebasis verstreut. Ist Teil des Thread-Safe Resource Managers (TSRM), der sicherstellt, dass PHP Variablen nicht über mehrere Threads hinweg mischt. Dies ist für uns nicht sehr wichtig. Ignorieren Sie es einfach, wenn Sie TSRMLS_CC (oder TSRMLS_DC) in Ihrem Code sehen. (Eine seltsame Sache, die Sie beachten müssen, ist, dass vor „Argument“ kein Komma steht. Dies liegt daran, dass das Makro unabhängig davon, ob Sie die Funktion mit Thread-Sicherheit erstellen, als leer oder als trsm_ls interpretiert wird. Daher ist das Komma Teil des Makros. )

Jetzt kommen wir zum Wichtigen: Die Zeichenfolge „sz|l“ markiert die von der Funktion empfangenen Parameter. :

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

Zusätzlich zu s, z, l gibt es noch weitere Logo-Typen, aber die meisten von ihnen können ihre Bedeutung anhand der Zeichen klar verstehen. Beispielsweise ist b ein boolescher Wert, d ein Double (Gleitkommazahl), a ein Array, f ein Callback (Funktion) und o ein Objekt.

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

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

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

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

if (offset < 0 || offset > haystack_len) {
    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset not contained in string");
    RETURN_FALSE;
}

这段代码做的事情很明显,如果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, "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

让我们继续解析代码:

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);
}

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

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

RETURN_LONG(found - haystack);

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

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);
}

我只引用在手册上写的”如果 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里面,字符串是使用’’结尾,就是说,最后一个字符被设置为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”。

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

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);
}

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

方法

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

Das obige ist der detaillierte Inhalt vonSo verwenden Sie interne PHP-Funktionen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn