Home >Backend Development >PHP Tutorial >Detailed explanation of the sample code of PHP7 scalar type declaration RFC
##1. Summary
This RFC recommends adding 4 new scalar type declarations: int, float, string and bool. These type declarations will be used consistently with PHP's original mechanism. The RFC also recommends adding a new optional instruction (declare(strict_type=1);) to each PHP file so that all function calls and statement returns in the same PHP file have a "strictly constrained" scalar type. Statement check. In addition, after turning on strict type constraints, calling extensions or PHP built-in functions will generate an E_RECOVERABLE_ERROR level error if parameter parsing fails. With these two features, the RFC hopes that writing PHP will become more accurate and documented.
## 2. Details
Scalar type declaration:
##No new added The
reserved words. Int, float, string and bool will be recognized as type declarations and are prohibited from being used as names for class/interface/trait, etc. New user scalar type declaration, implemented through the internal Fast Parameter Parsing API.
##strict_types/declare() directive
By default, all PHP files are in weak type checking mode. The new declare directive specifies the value of strict_types (1 or 0). 1 indicates strict type checking mode, which applies to function calls and return statements; 0 indicates weak type checking mode.
declare(strict_types=1) must be the first statement in the file. If this statement appears elsewhere in the file, a compilation error will be generated, and block mode is explicitly prohibited.
Similar to the encoding directive, but different from the ticks directive, the strict_types directive only affects the specified files and will not affect Other files included by it (via include
, etc.). This directive is compiled at runtime and cannot be modified. The way it works is to set a flag in the opcode so that function calls and return type checks comply with type constraints.
#Parameter type declaration
This directive affects all function calls, for example (strict verification mode):
<?php declare(strict_types=1); foo(); // strictly type-checked functioncall function foobar() { foo(); // strictly type-checked function call } class baz { function foobar() { foo(); // strictly type-checked function call } }
Comparison (weak verification mode)
<?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 } } ?>
Return type declaration:
The command will affect all files under the same file The return type of the function. For example (strict validation mode):
<?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 }} ?>
##Weak type checking behavior:
一个弱类型校验的函数调用,和PHP7之前的PHP版本是一致的(包括拓展和PHP内置函数)。通常,弱类型校验规则对于新的标量类型声明的处理是相同的,但是,唯一的例外是对NULL的处理。为了和我们现有类、调用、数组的类型声明保持一致,NULL不是默认的,除非它作为一个参数并且被显式赋值为NULL。
为了给不熟悉PHP现有的弱标量参数类型规则的读者,提供简短的总结。表格展示不同类型能够接受和转换的标量类型声明,NULL、arrays和resource不能接受标量类型声明,因此不在表格内。
*只有范围在PHP_INT_MIN和PHP_INT_MAX内的non-NaN float类型可以接受。(PHP7新增,可查看ZPP Failure on Overflow RFC)
?Non-numeric型字符串不被接受,Numeric型字符串跟随字符串的,也可以被接受,但是会产生一个notice。
?仅当它有toString方法时可以。
严格类型校验行为:
严格的类型校验调用拓展或者PHP内置函数,会改变zend_parse_parameters的行为。特别注意,失败的时候,它会产生E_RECOVERABLE_ERROR而不是E_WARNING。它遵循严格类型校验规则,而不是传统的弱类型校验规则。严格类型校验规则是非常直接的:只有当类型和指定类型声明匹配,它才会接受,否则拒绝。
有一个例外的是,宽泛类型转换是允许int变为float的,也就是说参数如果被声明为float类型,但是它仍然可以接受int参数。
<?php declare(strict_types=1); function add(float $a, float $b): float { return $a + $b;} add(1, 2); // float(3) ?>
在这种场景下,我们传递一个int参数给到定义接受float的函数,这个参数将会被转换为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("1foo", "2")); // int(3) // Notice: A non well formed numeric value encountered
但是,通过可选择指令declare开启严格类型校验后,在这个场景下,相同的调用将会失败。
<?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的对象处理机制采用了广泛类型检查方式,并不追求精确匹配和转换。
每个方法各有其优缺点。
这个提案中,默认采用弱类型校验机制,同时追加一个开关,允许转换为广泛类型校验机制(也就是严格类型校验机制)。
Why are both supported?
So far, most proponents of scalar type declarations require support for both strict type checking and weak typing. Verification does not only support one of them. This RFC makes weak type checking the default behavior and adds an optional directive to use strict type checking (in the same file). There are many reasons behind this choice.
A large portion of the PHP community seems to like Quan Static type. However, adding strict type checking to scalar type declarations will cause some problems:
(1) Causes obvious inconsistencies: Extensions and PHP built-in functions use weak type checking for scalar type parameters, however, user's PHP functions will use strict type checking.
(2) A considerable number of people prefer weak type checking and do not agree with this proposal, and they may prevent its implementation .
(3) Already existing code uses PHP’s weak types, which will be affected. If functions are required to add scalar type declarations to parameters, this will greatly increase the complexity of existing code bases, especially for library files.
There are still quite a few people here who like weak type checking , however, both adding strict type checking declarations and adding weak type checking declarations will cause some problems:
(1) Most of People who prefer strict type checking will not like this proposal and block its implementation.
(2) Limit the opportunities for static analysis. (Maybe it means optimization opportunities)
(3) It will hide some data loss bugs in automatic type conversion.
The third solution has been proposed, which is to add syntax to distinguish between weak type and strict type declaration. It will also bring some problems:
(1) People who don’t like weak types and strict type checking will be forced Libraries defined as strictly typed or weakly typed are handled separately.
(2) Like adding strict declarations, this will also be inconsistent with the expansion of the original weak type implementation and PHP built-in functions .
In order to solve the problems caused by these three solutions, this RFC proposes a fourth solution: each file is strictly defined Or weak type checking. It brings the following benefits:
(1) People can choose the type checking that suits them, that is, this scheme Hope to satisfy both strict and weak type checking camps.
(2) API will not be forced to adapt to a certain type declaration mode.
(3) Because the file uses a weak type checking scheme by default, the existing code base can be modified without destroying the code structure. case, add a scalar type declaration. It is also possible to have the code base add type declarations incrementally, or only for certain modules.
(4) Only a single syntax is needed to define a scalar type declaration.
(5) People who prefer strict type checking usually not only use this feature in user-defined functions, but also Also used in extensions and PHP built-in functions. In other words, PHP users will get a unified mechanism without the contradiction of strict scalar declaration.
(6) In strict type verification mode, expand the error level of type verification failure generated by PHP built-in functions, It will be consistent with the one generated by the user-defined function, which is E_RECOVERABLE_ERROR.
(7) It allows strictly typed and weakly typed code to be seamlessly integrated in a single code base.
##
The above is the detailed content of Detailed explanation of the sample code of PHP7 scalar type declaration RFC. For more information, please follow other related articles on the PHP Chinese website!