개발 과정에서 함수의 반환값 유형을 결정하고 변경하지 않아야 하는데, PHP는 약한 유형의 언어입니다.
그래서 PHP에는 이러한 구문 검증 기능이 없습니다. 함정.
예를 들어 다음 코드는
<?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. …. } ?>
getArticles 함수는 bool, int, array 등 다양한 조건에 따라 다양한 유형의 값을 반환합니다. 함수는 배열을 반환하고 그 배열을 사용하여 다른 작업을 수행할 것으로 예상됩니다.
그러나 함수 반환 값 유형이 고정되어 있지 않기 때문에 호출 시 예상치 못한 다양한 함정이 발생할 수 있습니다.
그래서 규제할 수 없으면 강제로 하면 된다고 생각했어요.
함수/메서드 반환 값은 그림과 같이 필수 유형일 수 있습니다.
은 int, array, bool의 네 가지 필수 유형 제한을 지원합니다. , 객체, 반환 값이 함수 선언에 있는 유형과 일치하지 않으면 경고가 발생합니다. 원래 오류를 던지고 싶었지만
이 너무 가혹하고 간주할 수 밖에 없다고 느꼈습니다. 예외는 오류가 아니기 때문에 대신 경고를 사용했습니다.
PHP 자체는 int 함수와 같은 구문을 지원하지 않으므로 이를 지원하려면 먼저 구문 구문 분석기를 가져와야 합니다.>>> >여기서 자세히 설명하지는 않겠습니다.
먼저 Zend/zend_언어_scanner.l 파일을 스캔하도록 구문을 수정하세요.
다음 코드를 추가하세요.
의미는 매우 간단합니다. scan 스캐너가 int, bool, object, resources 및 array라는 키워드를 스캔하면 해당 T_FUNCTION_*를 반환합니다. 이는<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; }
스캐너가 토큰에 따라 다른 처리를 수행하는 것입니다. 토큰은 먼저 .y 파일에서 Zend/zend_언어_parser 정의
에 의해 처리되어야 하며 다음 코드를 추가해야 합니다.
$$.u.EA.var는 함수 반환 유형을 저장합니다. 그리고 마지막으로 이를 사용하여 반환 값 유형을 일치시킵니다.………. %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; }
이렇게 하면 구문 해석기가 새로운 PHP 구문을 처리할 수 있습니다.
이것으로는 충분하지 않습니다. 함수 선언에 정의된 처리 논리도 수정해야 합니다.
PHP는 먼저 PHP 구문을 구문 분석하여 해당 opcode를 생성하고 필요한 환경을 저장합니다. 및 매개 변수 정보를 전역 변수로 실행하여 opcode를 실행 함수를 통해 하나씩 실행합니다.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; ……….
따라서 처리를 수행하려면 opcode에 함수 유형을 저장해야 합니다. op_array.fn_type = function_type;
op_array에는 fn_type이 없습니다. op_array의 구조를 수정하려면 zend_uint fn_type;
을 추가하세요. (opcode의 경우 C에서 어셈블리로 변환하는 것을 상상할 수 있습니다. 관련 기사도 있습니다. 내 블로그에서 참조할 수 있습니다)
마지막으로 수정해야 합니다. opcode는 함수를 파괴합니다. 함수의 반환은 T_RETURN 토큰을 생성합니다. T_RETURN은 반환 유형에 따라 다른 콜백 함수를 호출합니다.
3개의 콜백이 있습니다. 반환 값이 const 유형 data이면 ZEND_RETURN_SPEC_CONST_HANDLERZEND_RETURN_SPEC_CONST_HANDLER ZEND_RETURN_SPEC_TMP_HANDLER ZEND_RETURN_SPEC_VAR_HANDLER
반환 값은 $a를 반환하고 ZEND_RETURN_SPEC_VAR_HANDLER
따라서 이 세 개의 콜백 함수는 처리 논리를 추가합니다.
콜백 함수가 반환되기 전에 다음 코드를 추가합니다.
fn_type을 반환 값의 유형과 비교합니다. 일치하는 항목이 없으면 이 경고가 발생합니다.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 ); }
이미 패치를 했습니다. 현재는 php5.3 버전만 지원합니다. 필요하다면 사용해도 됩니다.
이 구문이 왜 공식적으로 지원되지 않는지는 모르겠지만 꽤 필요하다고 생각합니다.