Funktionsparameter
Der einfachste Weg, die vom Funktionsaufrufer übergebenen Parameter zu erhalten, ist die Verwendung der Funktion zend_parse_parameters(). Wir können die ersten paar Parameter der Funktion zend_parse_parameters() mithilfe von Makros im Kernel direkt generieren, in der Form: ZEND_NUM_ARGS() TSRMLS_CC. Beachten Sie, dass zwischen den beiden ein Leerzeichen, aber kein Komma steht. Wie aus dem Namen hervorgeht, repräsentiert ZEND_NUM_ARGS() die Anzahl der Parameter. Der nächste Parameter, der an die Funktion zend_parse_parameters() übergeben werden muss, ist ein String, der zur Formatierung verwendet wird, genau wie der erste Parameter von printf. Nachfolgend sind einige der am häufigsten verwendeten Symbole dargestellt.
type_spec ist eine Formatzeichenfolge, ihre allgemeine Bedeutung ist wie folgt:
Parameter repräsentiert den Typ
b Boolean
l Integer
d Gleitkomma Gleitkomma
s String String
r Ressource Ressource
a Array Array
o Objektinstanz Objekt
O Objektinstanz eines angegebenen Typs Objekt eines bestimmten Typs
z Unspezifischer zval Jeder Typ ~
Z Der zval** Typ
f stellt den Funktions- und Methodennamen dar. Es scheint, dass es so etwas in PHP5.1 nicht gibt...
Diese Funktion ist genau wie die Funktion printf() die Formatzeichenfolge. Die Formate entsprechen eins zu eins. Einige grundlegende Datentypen werden direkt Typen in der C-Sprache zugeordnet.
ZEND_FUNCTION(sample_getlong) {
long foo;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,"l", &foo) == FAILURE)
{
RETURN_ NULL() ;
}
php_printf("Der ganzzahlige Wert des Parameters ist: %ldn", foo);
RETURN_TRUE; Die Daten sind in der Regel gleich, es gibt jedoch Ausnahmen. Daher sollten wir das lange Array nicht in ein int einfügen, insbesondere auf einer 64-Bit-Plattform, da dies zu einigen Fehlern führt, die nicht einfach zu beheben sind. Daher sollten wir beim Empfang von Parametern über die Funktion zend_parse_parameter() Variablen der vom Kernel vereinbarten Typen als Träger verwenden.
Parameter entspricht dem Datentyp in C
b zend_bool
l long
d double
s char*, int Ersteres erhält den Zeiger, letzteres die Länge
r zval *
a zval*
o zval*
O zval*, zend_class_entry*
z zval*
Z zval**
Beachten Sie, dass alle zusammengesetzten Typparameter in der PHP-Sprache zval* erfordern. Typ Als Träger, da es sich um einige vom Kernel angepasste Datenstrukturen handelt. Wir müssen bestätigen, dass der Typ des Parameters und der Träger konsistent sind. Bei Bedarf kann eine Typkonvertierung durchgeführt werden, z. B. die Konvertierung des Arrays in ein stdClass-Objekt. Über die Typen „s“ und „O“ (europäischer Großbuchstabe) muss gesondert gesprochen werden, da beide zwei Träger benötigen. In den nächsten Kapiteln erfahren Sie mehr über die spezifische Implementierung von Objekten in PHP. Schreiben wir also eine Funktion um, die wir in Kapitel 5 definiert haben:
function sample_hello_world($name) {
echo "Hello $name!n"}
Beim Schreiben einer Erweiterung, wir müssen zend_parse_parameters() verwenden, um diese Zeichenfolge zu erhalten:
ZEND_FUNCTION(sample_hello_world) {
char *name;
if (zend_parse_parameters(ZEND_NUM_ARGS( ) TSRMLS_CC, "s",&name, &name_len) == FAILURE)
{
RETURN_NULL();
}
php_printf("Hallo ");
PHPWRITE(name, name_len); php_printf("!n");
}
Wenn die Anzahl der an die Funktion übergebenen Parameter geringer ist als die Anzahl der von zend_parse_parameters() zu empfangenden Parameter, schlägt sie fehl und gibt FAILURE zurück.
Wenn wir mehrere Parameter empfangen müssen, können wir die empfangenden Träger direkt in den Parametern von zend_parse_paramenters() auflisten, wie zum Beispiel:
function sample_hello_world($name, $greeting) {
echo "Hello $greeting $name!n";
}
sample_hello_world('John Smith', 'Mr.');
Dies sollte in der PHP-Erweiterung implementiert werden:
ZEND_FUNCTION( sample_hello_world) {
char *name;
int name_len;
char *greeting_len;if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss",&name, &name_len, &greeting, &greeting_len) == FAILURE) {
RETURN_NULL();
}
php_printf("Hallo ");
PHPWRITE(greeting, Greeting_len);
php_printf(" ");
PHPWRITE(name, name_len);
php_printf("!n"}
Zusätzlich zu den definierten Parametern Oben gibt es drei weitere Parameter, um unsere Fähigkeit zum Empfangen von Parametern zu verbessern:
Typmodifikator Bedeutung
| Werte.
! Wenn Sie eine Nullvariable in der PHP-Sprache erhalten, wird diese direkt in NULL in der C-Sprache konvertiert, anstatt sie in ein zval vom Typ IS_NULL zu kapseln.
/ Wenn die übergebene Variable einen zval mit anderen Variablen teilt und keine Referenz ist, wird sie gezwungen, den neuen zval zu trennen: is_ref__gc==0 und refcount__gc==1 🎜>Lassen Sie uns nun mit dem Umschreiben von sample_hello_world() fortfahren. Als nächstes verwenden wir die Standardwerte einiger Parameter, was in der PHP-Sprache wie folgt aussieht:
function sample_hello_world($name , $greeting='Mr./Ms.') {
echo "Hallo $greeting $name!n";
sample_hello_world('Ginger Rogers','Ms.'); sample_hello_world('Fred Astaire ');
Zu diesem Zeitpunkt können Sie nur einen Parameter an sample_hello_world übergeben, oder Sie können zwei vollständige Parameter übergeben. Wie können wir also dieselbe Funktion in der Erweiterungsfunktion implementieren? Wir müssen den Parameter (|) in zend_parse_parameters verwenden. Die Parameter vor diesem Parameter gelten als notwendig, und die folgenden Parameter gelten als nicht wesentlich. Wenn sie nicht übergeben werden, wird der Träger nicht geändert.
ZEND_FUNCTION(sample_hello_world) {
char *name;
int name_len;
char *greeting = „Mr./Mrs.“; „) – 1; > }
php_printf("Hallo ");
PHPWRITE(gruss, Greeting_len);
PHPWRITE(name, name_len); );
}
Wenn Sie den zweiten Parameter nicht übergeben, wird die Erweiterungsfunktion als Standard betrachtet und ändert den Vektor nicht. Daher müssen wir den Wert des Trägers selbst voreinstellen, der oft NULL ist, oder einen Wert, der sich auf die Funktionslogik bezieht. Jeder zval, einschließlich des zval vom Typ IS_NULL, muss eine bestimmte Menge an Speicherplatz belegen und benötigt CPU-Rechenressourcen, um Speicher dafür zu beantragen, ihn zu initialisieren und nach Abschluss seiner Arbeit freizugeben. Aber viel Code erkennt dies nicht. Es gibt eine Menge Code, der einen Nullwert in den IS_NULL-Typ von zval einschließt. Diese Operation kann in der erweiterten Entwicklung optimiert werden. Wir können den Parameter als NULL in der C-Sprache empfangen. Schauen wir uns den folgenden Code zu diesem Problem an:
ZEND_FUNCTION(sample_arg_fullnull) {
zval *val; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z",&val) == FAILURE) {
RETURN_NULL();
}
if (Z_TYPE_P(val) == IS_NULL) {
val = php_sample_make_defaultval(TSRMLS_C);
}
...
}
ZEND_FUNCTION (sample_arg_nullok) {
zval *val;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z!",
{
RETURN_NULL(
}
if (! val) {
val = php_sample_make_defaultval(
}
}
Die beiden Codeteile sehen auf den ersten Blick nicht sehr unterschiedlich aus, aber der erste Codeteil erfordert mehr CPU- und Speicherressourcen. Vielleicht ist diese Technik in normalen Zeiten nicht sehr nützlich, aber es ist besser, sie zu kennen, als sie nicht zu kennen.
Erzwungene Trennung
Wenn eine Variable an eine Funktion übergeben wird, unabhängig davon, ob sie referenziert ist oder nicht, wird ihr refcoung__gc-Attribut um eins erhöht und beträgt mindestens 2. Eine Kopie ist sie selbst und die andere ist die an die Funktion übergebene Kopie. Bevor dieser Wert geändert wird, ist es manchmal erforderlich, ihn im Voraus in zwei tatsächliche Kopien aufzuteilen. Dies ist die Rolle des Formatzeichens „/“. Dadurch wird das Copy-on-Write-zval im Voraus in zwei vollständige und unabhängige Kopien aufgeteilt, sodass wir es im folgenden Code nach Belieben bearbeiten können. Andernfalls müssen wir uns möglicherweise ständig daran erinnern, die empfangenen Parameter und andere Vorgänge zu trennen. Wie das NULL-Flag folgt dieser Modifikator dem Typ, den er beeinflussen soll. Ebenso wie das NULL-Flag wissen Sie erst, dass Sie diese Funktion benötigen
zend_get_arguments()
Wenn Sie möchten, dass Ihre Erweiterung mit älteren PHP-Versionen kompatibel ist oder Sie einfach nur zval als Träger zum Empfangen von Parametern verwenden möchten, können Sie die Funktion zend_get_parameters() zum Empfangen von Parametern in Betracht ziehen. zend_get_parameters() unterscheidet sich von zend_parse_parameters(). Wie wir aus dem Namen ersehen können, wird es direkt ohne Analyse abgerufen. Zunächst einmal wird nicht automatisch eine Typkonvertierung durchgeführt. Die Träger aller Parameter in der Erweiterungsimplementierung müssen sich das einfachste Beispiel ansehen:
ZEND_FUNCTION(sample_onearg) {
zval * firstarg ;
if (zend_get_parameters(ZEND_NUM_ARGS(), 1, &firstarg)== FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Mindestens 1 Parameter erwartet.");
}
/* Etwas mit firstarg machen... */
}
Zweitens gibt zend_get_parameters() selbst keinen Fehler aus, wenn der Empfang fehlschlägt, und kann auch nicht bequem den Standardwert für den Parameter verarbeiten. Der letzte Punkt besteht darin, dass es sich von zend_parse_parameters dadurch unterscheidet, dass es automatisch alle Zvals, die dem Kopieren beim Schreiben entsprechen, zwangsweise trennt, eine neue Kopie generiert und diese an die Funktion sendet. Wenn Sie die anderen Funktionen nutzen möchten, diese Funktion aber nicht benötigen, können Sie versuchen, die Funktion zend_get_parameters_ex() zum Empfangen von Parametern zu verwenden. Um die Variablen von Copy-on-Write nicht zu trennen, sind die Parameter von zend_get_parameters_ex() vom Typ zval** statt zval*. Diese Funktion wird vielleicht nicht sehr oft verwendet, wenn Sie auf extreme Probleme stoßen, aber sie ist sehr einfach zu verwenden:
ZEND_FUNCTION(sample_onearg) {
zval **firstarg; zend_get_parameters_ex(1, &firstarg) == FAILURE) {
WRONG_PARAM_COUNT;
}
/* Mach etwas mit firstarg... */
}
Beachten Sie, dass zend_get_parameters_ex kein ZEND_NUM_ARGS() erfordert Als Parameter wird er nicht mehr benötigt, da er zu einem späteren Zeitpunkt hinzugefügt wurde.
Das Makro WRONG_PARAM_COUNT wird auch im obigen Beispiel verwendet. Seine Funktion besteht darin, eine Fehlermeldung der Stufe E_WARNING auszulösen und diese automatisch zurückzugeben.
Variable Parameter
Es gibt zwei weitere zend_get_parameter_**-Funktionen, die speziell zur Lösung des Problems vieler Parameter verwendet werden oder die Anzahl der Parameter nicht im Voraus bekannt sein kann. Denken Sie über die Verwendung der Funktion var_dump() in der PHP-Sprache nach. Wir können ihr eine beliebige Anzahl von Parametern übergeben. Ihre Implementierung im Kernel sieht tatsächlich so aus:
ZEND_FUNCTION(var_dump) {
int i, argc = ZEND_NUM_ARGS ();
zval ***args;
args = (zval ***)safe_emalloc(argc, sizeof(zval **), 0); == 0 ||. zend_get_parameters_array_ex(argc, args) == FAILURE) {
efree(args);
WRONG_PARAM_COUNT;
}
for (i=0; i
}
efree(args);
}
Das Programm ermittelt zunächst die Anzahl der Parameter und beantragt dann eine entsprechende Speichergröße über die Funktion „safe_emalloc“, um diese Parameter vom Typ zvals ** zu speichern. Die Funktion zend_get_parameters_array_ex() wird hier verwendet, um die an die Funktion übergebenen Parameter in Argumente zu füllen. Sie haben vielleicht sofort gedacht, dass es auch eine Funktion namens zend_get_parameters_array() gibt. Der einzige Unterschied besteht darin, dass sie Parameter vom Typ zval* in args füllt und ZEND_NUM_ARGS() als Parameter benötigt.