이 RFC는 int, float, string 및 bool의 4가지 새로운 스칼라 유형 선언을 추가할 것을 제안합니다. 이러한 유형 선언은 PHP의 원래 메커니즘과 일관되게 사용됩니다. RFC는 또한 동일한 PHP 파일의 모든 함수 호출 및 명령문 반환이 "엄격히 제한된" 스칼라 유형을 갖도록 각 PHP 파일에 새로운 선택적 명령(declare(strict_type=1);)을 추가할 것을 권장합니다. 또한 엄격한 유형 제약 조건을 켠 후 매개변수 구문 분석에 실패하면 확장 기능이나 PHP 내장 함수를 호출하면 E_RECOVERABLE_ERROR 수준 오류가 생성됩니다. RFC는 이 두 가지 기능을 통해 PHP 작성이 더욱 정확해지고 문서화되기를 바라고 있습니다.
추천 튜토리얼: "PHP Tutorial"
스칼라 유형 선언:
새 예약어가 추가되지 않았습니다. Int, float, string 및 bool은 유형 선언으로 인식되며 클래스/인터페이스/특성 등의 이름으로 사용이 금지됩니다. 내부 Fast Parameter Parsing API를 통해 구현된 새로운 사용자 스칼라 유형 선언입니다.
strict_types/declare() 지시어
기본적으로 모든 PHP 파일은 약한 유형 검사 모드에 있습니다. 새로운 선언 지시문은 strict_types(1 또는 0)의 값을 지정합니다. 1은 함수 호출 및 return 문에 적용되는 엄격한 유형 검사 모드를 나타내고, 0은 약한 유형 검사 모드를 나타냅니다.
declare(strict_types=1)은 파일의 첫 번째 문이어야 합니다. 이 명령문이 파일의 다른 곳에 나타나면 컴파일 오류가 발생하고 블록 모드가 명시적으로 금지됩니다.
인코딩 지시어와 유사하지만 틱 지시어와는 다릅니다. strict_types 지시어는 지정된 파일에만 영향을 미치며 포함된 다른 파일에는 영향을 미치지 않습니다(include 등을 통해). 이 지시문은 런타임에 컴파일되며 수정할 수 없습니다. 작동 방식은 함수 호출과 반환 유형 검사가 유형 제약 조건을 준수하도록 opcode에 플래그를 설정하는 것입니다.
매개변수 유형 선언
이 명령어는 모든 함수 호출에 영향을 미칩니다. 예를 들어(엄격한 확인 모드):
<?php declare(strict_types=1); foo(); // strictly type-checked function call function foobar() { foo(); // strictly type-checked function call } class baz { function foobar() { foo(); // strictly type-checked function call } }
대비(약한 확인 모드)
<?php foo(); // weakly type-checked function call function foobar() { foo(); // weakly type-checked function call } class baz { function foobar() { foo(); // weakly type-checked function call } }
반환 유형 선언:
이 명령어는 동일한 파일에 영향을 미칩니다. 예를 들어(엄격한 확인 모드):
<?php declare(strict_types=1); function foobar(): int { return 1.0; // strictly type-checked return } class baz { function foobar(): int { return 1.0; // strictly type-checked return } }
<?php function foobar(): int { return 1.0; // weakly type-checked return } class baz { function foobar(): int { return 1.0; // weakly type-checked return } }
약한 유형 검사 동작:
약한 유형 검사를 사용하는 함수 호출은 PHP7 이전 버전(확장 및 PHP 내장 포함)과 일치합니다. 기능). 일반적으로 약한 유형 검사 규칙은 새로운 스칼라 유형 선언과 동일하지만 유일한 예외는 NULL 처리입니다. 기존 클래스, 호출 및 배열 유형 선언과 일관성을 유지하기 위해 NULL은 매개변수로 전달되고 명시적으로 NULL에 할당되지 않는 한 기본값이 아닙니다.
약한 스칼라 매개변수 유형에 대한 PHP의 기존 규칙에 익숙하지 않은 독자를 위해 간략한 요약을 제공합니다. 표에는 다양한 유형이 허용하고 변환할 수 있는 스칼라 유형 선언이 나와 있습니다. NULL, 배열 및 리소스는 스칼라 유형 선언을 허용할 수 없으므로 표에 포함되지 않습니다.
*PHP_INT_MIN 및 PHP_INT_MAX 범위에서 NaN이 아닌 부동 소수점 유형만 허용됩니다. (PHP7의 새로운 기능, 오버플로 RFC의 ZPP 실패 참조)
?숫자가 아닌 문자열은 허용되지 않습니다. 문자열 뒤에 오는 숫자 문자열도 허용되지만 알림이 생성됩니다.
? __toString 메소드가 있는 경우에만 가능합니다.
엄격한 유형 검사 동작:
엄격한 유형 검사는 zend_parse_parameters의 동작을 변경하는 확장 프로그램 또는 PHP 내장 함수를 호출합니다. 실패하면 E_WARNING 대신 E_RECOVERABLE_ERROR가 생성됩니다. 전통적인 약한 유형 검사 규칙 대신 엄격한 유형 검사 규칙을 따릅니다. 엄격한 유형 검사의 규칙은 매우 간단합니다. 유형이 지정된 유형 선언과 일치하는 경우에만 허용되고 그렇지 않으면 거부됩니다.
한 가지 예외는 와이드 유형 변환을 통해 int를 float로 변경할 수 있다는 것입니다. 즉, 매개변수가 float 유형으로 선언된 경우 int 매개변수를 계속 허용할 수 있습니다.
<?php declare(strict_types=1); function add(float $a, float $b): float { return $a + $b; } add(1, 2); // float(3)
이 시나리오에서는 float를 허용하도록 정의된 함수에 int 매개변수를 전달하고 이 매개변수는 float로 변환됩니다. 이외의 변환은 허용되지 않습니다.
숫자 2개를 더하는 함수를 만들어 보겠습니다.
add.php
<?php function add(int $a, int $b): int { return $a + $b; }
별도의 파일이라면 약한 타이핑을 통해 add 함수를 호출할 수 있습니다.
<?php require "add.php"; var_dump(add(1, 2)); // int(3) // floats are truncated by default var_dump(add(1.5, 2.5)); // int(3) //strings convert if there's a number part var_dump(add("1", "2")); // int(3)
기본적으로 약한 타입 선언은 변환을 허용하며, 전달된 값이 변환됩니다.
<?php require "add.php"; var_dump(add("1 foo", "2")); // int(3) // Notice: A non well formed numeric value encountered
그러나 선택적 선언 지시문을 통해 엄격한 유형 검사를 활성화한 후에는 이 시나리오에서 동일한 호출이 실패합니다.
<?php declare(strict_types=1); require "add.php"; var_dump(add(1, 2)); // int(3) var_dump(add(1.5, 2.5)); // int(3) // Catchable fatal error: Argument 1 passed to add() must be of the type integer, float given
지시어는 동일한 파일의 모든 함수 호출에 영향을 미칩니다. 호출된 함수가 이 파일에 정의되어 있는지 여부에 관계없이 엄격한 유형 검사 모드가 사용됩니다.
<?php declare(strict_types=1); $foo = substr(52, 1); // Catchable fatal error: substr() expects parameter 1 to be string, integer given
스칼라 유형 선언은 반환 값의 엄격한 유형 검사에도 사용할 수 있습니다.
<?php function foobar(): int { return 1.0; } var_dump(foobar()); // int(1)
在弱类型模式下,float被转为integer。
<?php declare(strict_types=1); function foobar(): int { return 1.0; } var_dump(foobar()); // Catchable fatal error: Return value of foobar() must be of the type integer, float returned
历史
PHP从PHP5.0开始已经有对支持class和interface参数类型声明,PHP5.1支持array以及PHP5.4支持callable。这些类型声明让PHP在执行的时候传入正确的参数,让函数签名具有更多的信息。
先前曾经想添加标量类型声明,例如Scalar Type Hints with Casts RFC,因为各种原因失败了:
(1)类型转换和校验机制,对于拓展和PHP内置函数不匹配。
(2)它遵循一个弱类型方法。
(3)它的“严格”弱类型修改尝试,既没有满足严格类型的粉丝期望,也没有满足弱类型的粉丝。
这个RFC尝试解决全部问题。
弱类型和强类型
在现代编程语言的实际应用中,有三种主要的方法去检查参数和返回值的类型:
(1)全严格类型检查(也就是不会有类型转换发生)。例如F#、GO、Haskell、Rust和Facebook的Hack的用法。
(2)广泛原始类型检查(“安全”的类型转换会发生)。例如Java、D和Pascal。他们允许广泛原始类型转换(隐式转换),也就是说,一个8-bit的integer可以根据函数参数需要,被隐形转换为一个16-bit的integer,而且int也可以被转换为float的浮点数。其他类型的隐式转换则不被允许。
(3)弱类型检查(允许所有类型转换,可能会引起警告),它被有限制地使用在C、C#、C++和Visual Basic中。它们尝试尽可能“不失败”,完成一次转换。
PHP在zend_parse_parameters的标量内部处理机制是采用了弱类型模式。PHP的对象处理机制采用了广泛类型检查方式,并不追求精确匹配和转换。
每个方法各有其优缺点。
这个提案中,默认采用弱类型校验机制,同时追加一个开关,允许转换为广泛类型校验机制(也就是严格类型校验机制)。
为什么两者都支持?
目前为止,大部分的标量类型声明的拥护者都要求同时支持严格类型校验和弱类型校验,并非仅仅支持其中一种。这份RFC,使得弱类型校验为默认行为,同时,添加一个可选的指令来使用严格类型校验(同一个文件中)。在这个选择的背后,有很多个原因。
PHP社区很大一部分人看起来很喜欢全静态类型。但是,添加严格类型校验的标量类型声明将会引起一些问题:
(1)引起明显的不一致性:拓展和PHP内置函数对标量类型参数使用弱类型校验,但是,用户的PHP函数将会使用严格类型校验。
(2)相当一部分人更喜欢弱类型校验,并不赞同这个提案,他们可能会阻止它的实施。
(3)已经存在的代码使用了PHP的弱类型,它会受到影响。如果要求函数添加标量类型声明到参数上,对于现有的代码库,这将大大增加复杂性,特别是对于库文件。
这里仍然有相当于一部分人是喜欢弱类型校验的,但是,添加严格类型校验声明和添加弱类型校验声明都会引起一些问题:
(1)大部分倾向于严格类型校验的人将不会喜欢这个提案,然后阻止它的实施。
(2)限制静态解析的机会。(可能是说,优化的机会)
(3)它会隐藏一些在类型自动转换中数据丢失的bug。
第三种方案被提出来了,就是添加区分弱类型和严格类型声明的语法。它也会带来一些问题:
(1)不喜欢弱类型和严格类型校验的人,会被强迫分别处理被定义为严格类型或者弱类型校验的库。
(2)像添加严格声明一样,这个也将和原来弱类型实现的拓展和PHP内置函数无法保持一致。
为了解决这三种方案带来的问题,这个RFC提出了第四种方案:每个文件各自定义严格或者弱类型校验。它带来了以下好处:
(1)人们可以选择适合他们的类型校验,也就是说,这个方案希望同时满足严格和弱类型校验两个阵营。
(2)API不会被强制适应某个类型声明模式。
(3)因为文件默认使用弱类型校验方案,已经存在的代码库,可以在不破坏代码结构的情况下,添加标量类型声明。也可以让代码库逐步添加类型声明,或者仅部分模块添加。
(4)只需要一个单一语法,就可以定义标量类型声明。
(5)更喜欢严格类型校验的人,通常,不仅将这个特性使用在用户定义的函数,同时也使用在拓展和PHP内置函数中。也就是说,PHP使用者会得到一个统一机制,而不会产生严格标量声明的矛盾。
(6) 엄격한 유형 확인 모드에서 확장 및 PHP 내장 함수에 의해 생성된 유형 확인 실패의 오류 수준은 사용자 정의 함수(둘 다 E_RECOVERABLE_ERROR)에 의해 생성된 수준과 일치합니다.
(7) 엄격한 유형의 코드와 약한 유형의 코드를 단일 코드 베이스에 원활하게 통합할 수 있습니다.
위 내용은 PHP7 스칼라 유형 선언 RFC 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!