>  기사  >  백엔드 개발  >  PHP는 강력한 형식의 함수 반환 값을 구현합니다.

PHP는 강력한 형식의 함수 반환 값을 구현합니다.

伊谢尔伦
伊谢尔伦원래의
2016-11-26 16:22:451720검색

개발 과정에서 함수의 반환값 유형을 결정하고 변경하지 않아야 하는데, 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 등 다양한 조건에 따라 다양한 유형의 값을 반환합니다. 함수는 배열을 반환하고 그 배열을 사용하여 다른 작업을 수행할 것으로 예상됩니다.

그러나 함수 반환 값 유형이 고정되어 있지 않기 때문에 호출 시 예상치 못한 다양한 함정이 발생할 수 있습니다.

그래서 규제할 수 없으면 강제로 하면 된다고 생각했어요.

함수/메서드 반환 값은 그림과 같이 필수 유형일 수 있습니다.

PHP는 강력한 형식의 함수 반환 값을 구현합니다.

은 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_HANDLER
ZEND_RETURN_SPEC_CONST_HANDLER
ZEND_RETURN_SPEC_TMP_HANDLER
ZEND_RETURN_SPEC_VAR_HANDLER
반환 값은 임시 데이터입니다. 예: return 1이면 ZEND_RETURN_SPEC_TMP_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 버전만 지원합니다. 필요하다면 사용해도 됩니다.

이 구문이 왜 공식적으로 지원되지 않는지는 모르겠지만 꽤 필요하다고 생각합니다.

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.