ホームページ >バックエンド開発 >PHPチュートリアル >PHP: PHP に関数強制型復帰を追加
開発プロセスでは、関数の戻り値の型を決定して変更する必要がありますが、PHP は型付けが弱い言語であるため、このような構文検証が行われず、多くの落とし穴が発生しました。
たとえば、次のコード:
<?phpfunction getArticles(...){ $arrData = array(); if($exp1){ return $arrData; }else if($exp2){ return 1; }else{ return false; }}$arrData =getArticles(...);foreach($arrData as $record){//do something.....}?>
getArticles 関数は、bool、int、配列など、さまざまな条件に従ってさまざまなタイプの値を返します。通常、このタイプの関数は配列を返し、それを使用します。しかし、関数の戻り値の型が固定されていないため、呼び出し時にさまざまな思わぬ落とし穴が発生する可能性があり、標準化できないので、それを強制的に実行する必要があると考えました。
関数/メソッドの戻り値の型を強制できます:
int function a(){ ...... return 1;}bool function b(){ ...... return false;}array function c(){ ...... return array();}object function d(){ ...... return new a();}
4 つの必須の型制限をサポートします: int、array、bool、object 戻り値が関数宣言の型と一致しない場合、警告がスローされます。本来はエラーをスローする予定でしたが、これは厳しすぎてエラーではなく例外としか考えられないので、警告を使用します。
PHP 自体は int 関数のような構文をサポートしていないため、それをサポートしたい場合は、まず構文パーサーを修正する必要があります。詳しくは説明しません。詳細はこちらを参照してください。最初に構文を変更します。Zend/zend_ language_scanner.l ファイルをスキャンします。
次のコードを追加します。
<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;}スキャナがキーワード int、bool、object、resource、array をスキャンするときの意味は非常に簡単です。対応する T_FUNCTION_* を返します。これは、トークンが異なると異なる方法で処理されるため、最初に Zend/zend_ language_parser.y ファイルに定義する必要があります
..........%token T_FUNCTION_RETURN_INT%token T_FUNCTION_RETURN_BOOL%token T_FUNCTION_RETURN_STRING%token T_FUNCTION_RETURN_OBJECT%token T_FUNCTION_RETURN_RESOURCE1然后增加token处理逻辑:1function: 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; }$$.u.EA。 var は関数の戻り値の型を格納し、最終的にそれを使用して戻り値を追跡します。構文インタープリターが新しい PHP 構文を処理できるように、値の型が一致します。これだけでは十分ではなく、関数宣言定義の処理ロジックも変更する必要があります 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; //保存函数类型,在语法解释器中增加的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;..........PHP はまず PHP 構文を解析して対応するオペコードを生成し、必要な環境とパラメーター情報をexecute_data グローバル変数、そして最後に、オペコードは実行関数を通じて 1 つずつ実行されるため、処理を行うには、オペコードに関数タイプを保存する必要があります。 op_array の構造を変更し、zend_uint fn_type を追加します。最後に、関数を破棄すると、トークン T_RETURN が生成され、戻り値の型に応じてさまざまなコールバック関数が呼び出されます。戻り値が const 型データの場合、ZEND_RETURN_SPEC_CONST_HANDLER の戻り値は一時データ (return 1 など)、ZEND_RETURN_SPEC_TMP_HANDLER 戻り値は変数 (return $a、ZEND_RETURN_SPEC_VAR_HANDLER など) です。これら 3 つのコールバック関数に処理ロジックを追加する必要があります。
コールバック関数 return の前に次のコードを追加します。
ZEND_RETURN_SPEC_CONST_HANDLERZEND_RETURN_SPEC_TMP_HANDLERZEND_RETURN_SPEC_VAR_HANDLERfn_type が戻り値の型と比較され、一致しない場合は、この警告がスローされます。すでにパッチを適用していますが、現在は php5.3 バージョンのみをサポートしています。必要に応じて試してください。なぜこの構文が正式にサポートされていないのかはわかりませんが、かなり必要だと思います。
パッチをダウンロードします: php-syntax.patch
続き: その後、私はバード兄弟と話しましたが、彼の答えは次のとおりです: 「このトピックは基本的にメールグループの生理的な投稿です... 1. PHP は型であるため, 多くの型は相互に変換できるので、暗黙的な変換が必要ですか? 変換にさまざまな変換ルールが含まれる場合、これは制限されすぎます。十分ではありません (さまざまなカスタム クラスと継承クラス) 3. 将来的に JIT を実行したい場合は、サポートすることを検討してください。」 この観点からすると、公式もこの問題にかなり巻き込まれています。変換を強制するのではなく、警告をスローして、変換するかどうかを開発者に決定させる方が良いでしょうか?