Heim  >  Artikel  >  Backend-Entwicklung  >  PHP implementiert einen stark typisierten Funktionsrückgabewert

PHP implementiert einen stark typisierten Funktionsrückgabewert

伊谢尔伦
伊谢尔伦Original
2016-11-26 16:22:451720Durchsuche

Während des Entwicklungsprozesses sollte der Rückgabewerttyp der Funktion bestimmt und unverändert bleiben, aber PHP ist eine schwach typisierte Sprache

Aus diesem Grund verfügt PHP nicht über eine solche Syntaxüberprüfung Fallstricke.

Zum Beispiel der folgende Code:

<?php
function getArticles(…){
$arrData = array();
if($exp1){
return $arrData;
}else if($exp2){
return 1;
}else{
return false;
}
}
$arrData =getArticles(…);
foreach($arrData as $record){
//do something.
….
}
?>

Die Funktion getArticles gibt verschiedene Arten von Werten gemäß unterschiedlichen Bedingungen zurück, einschließlich Bool, Int und Arrays Von der Funktion wird erwartet, dass sie ein Array zurückgibt und das Array dann für einige andere Operationen verwendet.

Da der Typ des Rückgabewerts der Funktion jedoch nicht festgelegt ist, können beim Aufruf verschiedene unerwartete Fallstricke auftreten,

Da dachte ich mir, denn wenn du es nicht regulieren kannst, dann erzwinge es einfach.

Der Rückgabewert der Funktion/Methode kann von einem obligatorischen Typ sein, wie in der Abbildung gezeigt.

PHP implementiert einen stark typisierten Funktionsrückgabewert

unterstützt vier obligatorische Typbeschränkungen: int, array, bool , Objekt, wenn der Rückgabewert nicht mit dem Typ in der Funktionsdeklaration übereinstimmt, wird eine Warnung ausgegeben. Ursprünglich wollte ich einen Fehler auslösen, aber ich hatte das Gefühl, dass

zu hart war und nur berücksichtigt werden konnte ausnahmsweise kein Fehler, daher habe ich stattdessen warning verwendet.

PHP selbst unterstützt keine Syntax wie die int-Funktion. Um sie zu unterstützen, müssen Sie sich also zuerst den Syntax-Parser besorgen. Den Syntax-Parser können Sie hier>>> anzeigen >Ich werde hier nicht auf Details eingehen.

Ändern Sie zunächst die Syntax, um die Zend/zend_lingual_scanner.l-Datei zu scannen

Fügen Sie den folgenden Code hinzu:

Die Die Bedeutung ist sehr einfach: Wenn der Scanner die Schlüsselwörter int, bool, object, resources und array scannt, gibt er das entsprechende T_FUNCTION_* zurück.
<ST_IN_SCRIPTING>”int” {
return T_FUNCTION_RETURN_INT;
}
<ST_IN_SCRIPTING>”bool” {
return T_FUNCTION_RETURN_OBJECT;
}
<ST_IN_SCRIPTING>”object” {
return T_FUNCTION_RETURN_OBJECT;
}
<ST_IN_SCRIPTING>”resource” {
return T_FUNCTION_RETURN_RESOURCE;
}

Der Scanner führt je nach Token unterschiedliche Verarbeitungen durch. Das Token muss zuerst von Zend/zend_lingual_parser verarbeitet werden. Definieren Sie

in der .y-Datei und fügen Sie den folgenden Code hinzu:

$$.u.EA.var speichert den Rückgabetyp der Funktion. und verwendet es schließlich, um den Rückgabewerttyp abzugleichen.
……….
%token T_FUNCTION_RETURN_INT
%token T_FUNCTION_RETURN_BOOL
%token T_FUNCTION_RETURN_STRING
%token T_FUNCTION_RETURN_OBJECT
%token T_FUNCTION_RETURN_RESOURCE
1
然后增加token处理逻辑:
1
function:
T_FUNCTION { $$.u.opline_num = CG(zend_lineno);$$.u.EA.var  = 0; }
|   T_FUNCTION_RETURN_INT T_FUNCTION {
$$.u.opline_num = CG(zend_lineno);
$$.u.EA.var = IS_LONG;
}
|   T_FUNCTION_RETURN_BOOL T_FUNCTION {
$$.u.opline_num = CG(zend_lineno);
$$.u.EA.var = IS_BOOL;
}
|   T_FUNCTION_RETURN_STRING T_FUNCTION {
$$.u.opline_num = CG(zend_lineno);
$$.u.EA.var = IS_STRING;
}
|   T_FUNCTION_RETURN_OBJECT T_FUNCTION {
$$.u.opline_num = CG(zend_lineno);
$$.u.EA.var = IS_OBJECT;
}
|   T_FUNCTION_RETURN_RESOURCE T_FUNCTION {
$$.u.opline_num = CG(zend_lineno);
$$.u.EA.var = IS_RESOURCE;
}
|   T_ARRAY T_FUNCTION {
$$.u.opline_num = CG(zend_lineno);
$$.u.EA.var = IS_ARRAY;
}

Auf diese Weise kann der Syntaxinterpreter mit unserer neuen PHP-Syntax umgehen.

Das reicht nicht aus, Sie müssen auch die durch die Funktionsdeklaration definierte Verarbeitungslogik ändern

PHP analysiert zunächst die PHP-Syntax, um den entsprechenden Opcode zu generieren, und speichert die erforderliche Umgebung und Parameterinformationen zu den globalen Ausführungsdaten. In der Variablen wird der Opcode einzeln durch die Ausführungsfunktion ausgeführt.
Zend/zend_compile.c ::zend_do_begin_function_declaration
……
zend_op_array op_array;
char *name = function_name->u.constant.value.str.val;
int name_len = function_name->u.constant.value.str.len;
int function_type  = function_token->u.EA.var; //保存函数类型,在语法解释器中增加的: $$.u.EA.var = IS_LONG;
int function_begin_line = function_token->u.opline_num;
……
op_array.function_name = name;
op_array.fn_type = function_type; //将类型保存到op_array中,
op_array.return_reference = return_reference;
op_array.fn_flags |= fn_flags;
op_array.pass_rest_by_reference = 0;
……….

Daher muss für die Verarbeitung der Typ der Funktion im Opcode gespeichert werden: op_array. fn_type = function_type;

op_array hat kein fn_type, um die Struktur von op_array zu ändern, fügen Sie zend_uint fn_type;

hinzu (Was den Opcode betrifft, können Sie sich vorstellen, von c nach Assembly zu konvertieren. Ich habe auch Verwandte Artikel in meinem Blog, Sie können darauf verweisen)

Schließlich muss der Opcode geändert werden. Die Rückgabe der Funktion generiert das Token T_RETURN. T_RETURN ruft je nach Rückgabetyp unterschiedliche Rückruffunktionen auf.

Es gibt drei Rückrufe, wenn der Rückgabewert ein Datentyp const ist, dann ZEND_RETURN_SPEC_CONST_HANDLER
ZEND_RETURN_SPEC_CONST_HANDLER
ZEND_RETURN_SPEC_TMP_HANDLER
ZEND_RETURN_SPEC_VAR_HANDLER
Der Rückgabewert sind temporäre Daten, wie zum Beispiel: Rückgabe 1, dann ZEND_RETURN_SPEC_TMP_HANDLER

Der Rückgabewert ist eine Variable, wie zum Beispiel: return $a, then ZEND_RETURN_SPEC_VAR_HANDLER

Also fügen diese drei Rückruffunktionen Verarbeitungslogik hinzu:

Fügen Sie den folgenden Code hinzu, bevor die Rückruffunktion

fn_type zum Vergleich mit dem Typ des Rückgabewerts. Wenn keine Übereinstimmung vorliegt, wird diese Warnung ausgegeben.

if((EG(active_op_array)->fn_type > 0) && Z_TYPE_P(retval_ptr) != EG(active_op_array)->fn_type){
php_error_docref0(NULL TSRMLS_DC,E_WARNING, “function name %s return a wrong type.”, EG(active_op_array)->function_name );
}
Ich habe es bereits gepatcht. Derzeit unterstützt es nur die PHP5.3-Version. Sie können damit spielen, wenn Sie es benötigen.

Ich weiß nicht, warum diese Syntax nicht offiziell unterstützt wird, aber ich denke, dass sie durchaus notwendig ist.

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